winrm-fs 1.0.1 → 1.0.2
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/.gitignore +10 -10
- data/.rspec +3 -3
- data/.rubocop.yml +9 -9
- data/.travis.yml +9 -9
- data/Gemfile +5 -5
- data/LICENSE +202 -202
- data/README.md +79 -79
- data/Rakefile +28 -28
- data/VERSION +1 -1
- data/Vagrantfile +9 -9
- data/appveyor.yml +39 -39
- data/bin/rwinrmcp +86 -86
- data/changelog.md +54 -51
- data/lib/winrm-fs.rb +28 -28
- data/lib/winrm-fs/core/file_transporter.rb +527 -527
- data/lib/winrm-fs/core/tmp_zip.rb +177 -166
- data/lib/winrm-fs/exceptions.rb +28 -28
- data/lib/winrm-fs/file_manager.rb +118 -117
- data/lib/winrm-fs/scripts/check_files.ps1.erb +49 -49
- data/lib/winrm-fs/scripts/checksum.ps1.erb +13 -13
- data/lib/winrm-fs/scripts/create_dir.ps1.erb +6 -6
- data/lib/winrm-fs/scripts/delete.ps1.erb +6 -6
- data/lib/winrm-fs/scripts/download.ps1.erb +8 -8
- data/lib/winrm-fs/scripts/exists.ps1.erb +10 -10
- data/lib/winrm-fs/scripts/extract_files.ps1.erb +52 -52
- data/lib/winrm-fs/scripts/scripts.rb +31 -31
- data/spec/config-example.yml +2 -2
- data/spec/integration/file_manager_spec.rb +224 -224
- data/spec/integration/tmp_zip_spec.rb +26 -26
- data/spec/matchers.rb +58 -58
- data/spec/spec_helper.rb +71 -71
- data/spec/unit/tmp_zip_spec.rb +79 -79
- data/winrm-fs.gemspec +37 -37
- metadata +3 -3
@@ -1,166 +1,177 @@
|
|
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 =
|
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 [
|
102
|
-
#
|
103
|
-
# @api private
|
104
|
-
def
|
105
|
-
Pathname.glob(dir
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
#
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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 = clean_dirname(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 [Pathname] the pathname object representing dirname that
|
102
|
+
# doesn't have any of those ~ in it
|
103
|
+
# @api private
|
104
|
+
def clean_dirname(dir)
|
105
|
+
paths = Pathname.glob(dir)
|
106
|
+
if paths.length != 1
|
107
|
+
fail "Expected Pathname.glob(dir) to return only dir, got #{paths}"
|
108
|
+
end
|
109
|
+
paths.first
|
110
|
+
end
|
111
|
+
|
112
|
+
# @return [Array<Pathname] all recursive files under the base
|
113
|
+
# directory, excluding directories
|
114
|
+
# @api private
|
115
|
+
def entries
|
116
|
+
Pathname.glob(dir.join('**/*')).delete_if(&:directory?).sort
|
117
|
+
end
|
118
|
+
|
119
|
+
# (see Logging.log_subject)
|
120
|
+
# @api private
|
121
|
+
def log_subject
|
122
|
+
@log_subject ||= [self.class.to_s.split('::').last, path].join('::')
|
123
|
+
end
|
124
|
+
|
125
|
+
# Adds all file entries to the Zip output stream.
|
126
|
+
#
|
127
|
+
# @param zos [Zip::OutputStream] zip output stream
|
128
|
+
# @api private
|
129
|
+
def produce_zip_entries(zos)
|
130
|
+
entries.each do |entry|
|
131
|
+
entry_path = entry.sub(/#{dir}\//i, '')
|
132
|
+
logger.debug "+++ Adding #{entry_path}"
|
133
|
+
zos.put_next_entry(
|
134
|
+
zip_entry(entry_path),
|
135
|
+
nil, nil, ::Zip::Entry::DEFLATED, Zlib::BEST_COMPRESSION)
|
136
|
+
entry.open('rb') { |src| IO.copy_stream(src, zos) }
|
137
|
+
end
|
138
|
+
logger.debug '=== All files added.'
|
139
|
+
end
|
140
|
+
|
141
|
+
# Writes out a temporary Zip file.
|
142
|
+
#
|
143
|
+
# @api private
|
144
|
+
def write_zip
|
145
|
+
logger.debug 'Populating files'
|
146
|
+
Zip::OutputStream.write_buffer(NoDupIO.new(zip_io)) do |zos|
|
147
|
+
produce_zip_entries(zos)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def zip_entry(entry_path)
|
152
|
+
Zip::Entry.new(
|
153
|
+
zip_io.path,
|
154
|
+
entry_path.to_s,
|
155
|
+
nil, nil, nil, nil, nil, nil,
|
156
|
+
::Zip::DOSTime.new(2000)
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Simple delegate wrapper to prevent `#dup` calls being made on IO
|
161
|
+
# objects. This is used to bypass an issue in the `Zip::Outputstream`
|
162
|
+
# constructor where an incoming IO is duplicated, leading to races
|
163
|
+
# on flushing the final stream to disk.
|
164
|
+
#
|
165
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
166
|
+
# @api private
|
167
|
+
class NoDupIO < SimpleDelegator
|
168
|
+
# @return [self] returns self and does *not* return a duplicate
|
169
|
+
# object
|
170
|
+
def dup
|
171
|
+
self
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
data/lib/winrm-fs/exceptions.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
|
-
# Copyright 2015 Shawn Neal <sneal@sneal.net>
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
|
17
|
-
module WinRM
|
18
|
-
module FS
|
19
|
-
# WinRM-FS base class for errors
|
20
|
-
class WinRMFSError < StandardError; end
|
21
|
-
|
22
|
-
# Error that occurs when a file upload fails
|
23
|
-
class WinRMUploadError < WinRMFSError; end
|
24
|
-
|
25
|
-
# Error that occurs when a file download fails
|
26
|
-
class WinRMDownloadError < WinRMFSError; end
|
27
|
-
end
|
28
|
-
end
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright 2015 Shawn Neal <sneal@sneal.net>
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module WinRM
|
18
|
+
module FS
|
19
|
+
# WinRM-FS base class for errors
|
20
|
+
class WinRMFSError < StandardError; end
|
21
|
+
|
22
|
+
# Error that occurs when a file upload fails
|
23
|
+
class WinRMUploadError < WinRMFSError; end
|
24
|
+
|
25
|
+
# Error that occurs when a file download fails
|
26
|
+
class WinRMDownloadError < WinRMFSError; end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,117 +1,118 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
|
-
# Copyright 2015 Shawn Neal <sneal@sneal.net>
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
|
17
|
-
require 'winrm'
|
18
|
-
require_relative 'scripts/scripts'
|
19
|
-
require_relative 'core/file_transporter'
|
20
|
-
|
21
|
-
module WinRM
|
22
|
-
module FS
|
23
|
-
# Perform file transfer operations between a local machine and winrm endpoint
|
24
|
-
class FileManager
|
25
|
-
# Creates a new FileManager instance
|
26
|
-
# @param [WinRM::Connection] WinRM web connection client
|
27
|
-
def initialize(connection)
|
28
|
-
@connection = connection
|
29
|
-
@logger = connection.logger
|
30
|
-
end
|
31
|
-
|
32
|
-
# Gets the MD5 checksum of the specified file if it exists,
|
33
|
-
# otherwise ''
|
34
|
-
# @param [String] The remote file path
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
#
|
43
|
-
# @
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
#
|
52
|
-
# @
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
#
|
61
|
-
# @param [String] The full path
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
# @
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# '
|
84
|
-
#
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
# @yieldparam [Fixnum]
|
106
|
-
# @yieldparam [
|
107
|
-
# @yieldparam [String]
|
108
|
-
# @
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
file_transporter.
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright 2015 Shawn Neal <sneal@sneal.net>
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'winrm'
|
18
|
+
require_relative 'scripts/scripts'
|
19
|
+
require_relative 'core/file_transporter'
|
20
|
+
|
21
|
+
module WinRM
|
22
|
+
module FS
|
23
|
+
# Perform file transfer operations between a local machine and winrm endpoint
|
24
|
+
class FileManager
|
25
|
+
# Creates a new FileManager instance
|
26
|
+
# @param [WinRM::Connection] WinRM web connection client
|
27
|
+
def initialize(connection)
|
28
|
+
@connection = connection
|
29
|
+
@logger = connection.logger
|
30
|
+
end
|
31
|
+
|
32
|
+
# Gets the MD5 checksum of the specified file if it exists,
|
33
|
+
# otherwise ''
|
34
|
+
# @param [String] The remote file path
|
35
|
+
# @parms [String] The digest method
|
36
|
+
def checksum(path, digest = 'MD5')
|
37
|
+
@logger.debug("checksum with #{digest}: #{path}")
|
38
|
+
script = WinRM::FS::Scripts.render('checksum', path: path, digest: digest)
|
39
|
+
@connection.shell(:powershell) { |e| e.run(script).stdout.chomp }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create the specifed directory recursively
|
43
|
+
# @param [String] The remote dir to create
|
44
|
+
# @return [Boolean] True if successful, otherwise false
|
45
|
+
def create_dir(path)
|
46
|
+
@logger.debug("create_dir: #{path}")
|
47
|
+
script = WinRM::FS::Scripts.render('create_dir', path: path)
|
48
|
+
@connection.shell(:powershell) { |e| e.run(script).exitcode == 0 }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Deletes the file or directory at the specified path
|
52
|
+
# @param [String] The path to remove
|
53
|
+
# @return [Boolean] True if successful, otherwise False
|
54
|
+
def delete(path)
|
55
|
+
@logger.debug("deleting: #{path}")
|
56
|
+
script = WinRM::FS::Scripts.render('delete', path: path)
|
57
|
+
@connection.shell(:powershell) { |e| e.run(script).exitcode == 0 }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Downloads the specified remote file to the specified local path
|
61
|
+
# @param [String] The full path on the remote machine
|
62
|
+
# @param [String] The full path to write the file to locally
|
63
|
+
def download(remote_path, local_path)
|
64
|
+
@logger.debug("downloading: #{remote_path} -> #{local_path}")
|
65
|
+
script = WinRM::FS::Scripts.render('download', path: remote_path)
|
66
|
+
output = @connection.shell(:powershell) { |e| e.run(script) }
|
67
|
+
return false if output.exitcode != 0
|
68
|
+
contents = output.stdout.gsub('\n\r', '')
|
69
|
+
out = Base64.decode64(contents)
|
70
|
+
IO.binwrite(local_path, out)
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
# Checks to see if the given path exists on the target file system.
|
75
|
+
# @param [String] The full path to the directory or file
|
76
|
+
# @return [Boolean] True if the file/dir exists, otherwise false.
|
77
|
+
def exists?(path)
|
78
|
+
@logger.debug("exists?: #{path}")
|
79
|
+
script = WinRM::FS::Scripts.render('exists', path: path)
|
80
|
+
@connection.shell(:powershell) { |e| e.run(script).exitcode == 0 }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Gets the current user's TEMP directory on the remote system, for example
|
84
|
+
# 'C:/Windows/Temp'
|
85
|
+
# @return [String] Full path to the temp directory
|
86
|
+
def temp_dir
|
87
|
+
@guest_temp ||= begin
|
88
|
+
(@connection.shell(:powershell) { |e| e.run('$env:TEMP') }).stdout.chomp.gsub('\\', '/')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Upload one or more local files and directories to a remote directory
|
93
|
+
# @example copy a single file to a winrm endpoint
|
94
|
+
#
|
95
|
+
# file_manager.upload('/Users/sneal/myfile.txt', 'c:/foo/myfile.txt')
|
96
|
+
#
|
97
|
+
# @example copy a single directory to a winrm endpoint
|
98
|
+
#
|
99
|
+
# file_manager.upload('c:/dev/my_dir', '$env:AppData')
|
100
|
+
#
|
101
|
+
# @param [String] A path to a local directory or file that will be copied
|
102
|
+
# to the remote Windows box.
|
103
|
+
# @param [String] The target directory or file
|
104
|
+
# This path may contain powershell style environment variables
|
105
|
+
# @yieldparam [Fixnum] Number of bytes copied in current payload sent to the winrm endpoint
|
106
|
+
# @yieldparam [Fixnum] The total number of bytes to be copied
|
107
|
+
# @yieldparam [String] Path of file being copied
|
108
|
+
# @yieldparam [String] Target path on the winrm endpoint
|
109
|
+
# @return [Fixnum] The total number of bytes copied
|
110
|
+
def upload(local_path, remote_path, &block)
|
111
|
+
@connection.shell(:powershell) do |shell|
|
112
|
+
file_transporter ||= WinRM::FS::Core::FileTransporter.new(shell)
|
113
|
+
file_transporter.upload(local_path, remote_path, &block)[0]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|