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.
@@ -0,0 +1,79 @@
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 'winrm-fs/core/tmp_zip'
20
+
21
+ describe WinRM::FS::Core::TmpZip do
22
+ let(:src_dir) do
23
+ tmpdir = Pathname.new(Dir.mktmpdir)
24
+ @tmpdirs << tmpdir
25
+ src_dir = tmpdir.join('src')
26
+ sub_dir = src_dir.join('veggies')
27
+
28
+ src_dir.mkpath
29
+ create_local_file(src_dir.join('apple.txt'), 'appleapple')
30
+ create_local_file(src_dir.join('banana.txt'), 'bananabanana')
31
+ create_local_file(src_dir.join('cherry.txt'), 'cherrycherry')
32
+ sub_dir.mkpath
33
+ create_local_file(sub_dir.join('carrot.txt'), 'carrotcarrot')
34
+ src_dir
35
+ end
36
+
37
+ let(:tmp_zip) { WinRM::FS::Core::TmpZip.new(src_dir) }
38
+
39
+ before { @tmpdirs = [] }
40
+
41
+ after do
42
+ @tmpdirs.each(&:rmtree)
43
+ tmp_zip.unlink if tmp_zip.path
44
+ end
45
+
46
+ it '#path returns path to created zip file' do
47
+ expect(tmp_zip.path.file?).to eq true
48
+ end
49
+
50
+ it '#unlink removes the file' do
51
+ path = tmp_zip.path
52
+ expect(path.file?).to eq true
53
+
54
+ tmp_zip.unlink
55
+
56
+ expect(path.file?).to eq false
57
+ expect(tmp_zip.path).to eq nil
58
+ end
59
+
60
+ describe 'for a zip file containing the base directory' do
61
+ let(:tmp_zip) { WinRM::FS::Core::TmpZip.new(src_dir) }
62
+
63
+ it 'contains the input entries' do
64
+ zip = Zip::File.new(tmp_zip.path)
65
+
66
+ expect(zip.map(&:name).sort).to eq(
67
+ ['apple.txt', 'banana.txt', 'cherry.txt', 'veggies/carrot.txt']
68
+ )
69
+ expect(zip.read('apple.txt')).to eq 'appleapple'
70
+ expect(zip.read('banana.txt')).to eq 'bananabanana'
71
+ expect(zip.read('cherry.txt')).to eq 'cherrycherry'
72
+ expect(zip.read('veggies/carrot.txt')).to eq 'carrotcarrot'
73
+ end
74
+ end
75
+
76
+ def create_local_file(path, content)
77
+ path.open('wb') { |file| file.write(content) }
78
+ end
79
+ end
data/winrm-fs.gemspec CHANGED
@@ -29,7 +29,8 @@ Gem::Specification.new do |s|
29
29
  s.add_runtime_dependency 'erubis', '~> 2.7'
30
30
  s.add_runtime_dependency 'logging', '~> 1.6', '>= 1.6.1'
31
31
  s.add_runtime_dependency 'rubyzip', '~> 1.1'
32
- s.add_runtime_dependency 'winrm', '~> 1.3.0'
32
+ s.add_runtime_dependency 'winrm', '~> 1.5'
33
+ s.add_development_dependency 'pry'
33
34
  s.add_development_dependency 'rspec', '~> 3.0.0'
34
35
  s.add_development_dependency 'rake', '~> 10.3.2'
35
36
  s.add_development_dependency 'rubocop', '~> 0.28.0'
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.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shawn Neal
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-11 00:00:00.000000000 Z
12
+ date: 2016-01-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: erubis
@@ -65,14 +65,28 @@ dependencies:
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.3.0
68
+ version: '1.5'
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.3.0
75
+ version: '1.5'
76
+ - !ruby/object:Gem::Dependency
77
+ name: pry
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
76
90
  - !ruby/object:Gem::Dependency
77
91
  name: rspec
78
92
  requirement: !ruby/object:Gem::Requirement
@@ -137,28 +151,29 @@ files:
137
151
  - Rakefile
138
152
  - VERSION
139
153
  - Vagrantfile
140
- - benchmark.rb
154
+ - appveyor.yml
141
155
  - bin/rwinrmcp
142
156
  - changelog.md
143
157
  - lib/winrm-fs.rb
144
- - lib/winrm-fs/core/command_executor.rb
145
- - lib/winrm-fs/core/file_uploader.rb
146
- - lib/winrm-fs/core/temp_zip_file.rb
147
- - lib/winrm-fs/core/upload_orchestrator.rb
158
+ - lib/winrm-fs/core/file_transporter.rb
159
+ - lib/winrm-fs/core/tmp_zip.rb
148
160
  - lib/winrm-fs/exceptions.rb
149
161
  - lib/winrm-fs/file_manager.rb
162
+ - lib/winrm-fs/scripts/check_files.ps1.erb
150
163
  - lib/winrm-fs/scripts/checksum.ps1.erb
151
164
  - lib/winrm-fs/scripts/create_dir.ps1.erb
152
- - lib/winrm-fs/scripts/decode_file.ps1.erb
165
+ - lib/winrm-fs/scripts/decode_files.ps1.erb
153
166
  - lib/winrm-fs/scripts/delete.ps1.erb
154
167
  - lib/winrm-fs/scripts/download.ps1.erb
155
168
  - lib/winrm-fs/scripts/exists.ps1.erb
156
169
  - lib/winrm-fs/scripts/scripts.rb
157
170
  - spec/config-example.yml
158
- - spec/file_manager_spec.rb
171
+ - spec/integration/file_manager_spec.rb
172
+ - spec/integration/tmp_zip_spec.rb
159
173
  - spec/matchers.rb
160
174
  - spec/spec_helper.rb
161
- - spec/temp_zip_file_spec.rb
175
+ - spec/unit/file_transporter_spec.rb
176
+ - spec/unit/tmp_zip_spec.rb
162
177
  - winrm-fs.gemspec
163
178
  homepage: http://github.com/WinRb/winrm-fs
164
179
  licenses: []
data/benchmark.rb DELETED
@@ -1,20 +0,0 @@
1
- # encoding: UTF-8
2
- require 'winrm-fs'
3
- require 'benchmark'
4
-
5
- def files
6
- # This is a fairly short list of small files, may also want a benchmark with larger files
7
- `git ls-files`.lines.map(&:strip)
8
- end
9
-
10
- def create_zip(factory, file)
11
- WinRM::FS::Core::TempZipFile.new(Dir.pwd, zip_file: file, via: factory, X: true) do | temp_zip |
12
- temp_zip.add(*files)
13
- end
14
- end
15
-
16
- Benchmark.bm do | benchmark |
17
- benchmark.report('zip cmd') { `git ls-files | zip zip_command.zip -X --names-stdin` }
18
- benchmark.report('shell') { create_zip(:shell, 'shell.zip') }
19
- benchmark.report('ruby') { create_zip(:rubyzip, 'ruby.zip') }
20
- end
@@ -1,74 +0,0 @@
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
- module Core
20
- # Executes commands used by the WinRM file management module
21
- class CommandExecutor
22
- def initialize(service)
23
- @service = service
24
- end
25
-
26
- def open
27
- @shell = @service.open_shell
28
- @shell_open = true
29
- end
30
-
31
- def close
32
- @service.close_shell(@shell) if @shell
33
- @shell_open = false
34
- end
35
-
36
- def run_powershell(script)
37
- assert_shell_is_open
38
- run_cmd('powershell', ['-encodedCommand', encode_script(safe_script(script))])
39
- end
40
-
41
- def run_cmd(command, arguments = [])
42
- assert_shell_is_open
43
- result = nil
44
- @service.run_command(@shell, command, arguments) do |command_id|
45
- result = @service.get_command_output(@shell, command_id)
46
- end
47
- assert_command_success(command, result)
48
- result.stdout
49
- end
50
-
51
- private
52
-
53
- def assert_shell_is_open
54
- fail 'You must call open before calling any run methods' unless @shell_open
55
- end
56
-
57
- def assert_command_success(command, result)
58
- return if result[:exitcode] == 0 && result.stderr.length == 0
59
- fail WinRMUploadError, command + '\n' + result.output
60
- end
61
-
62
- def encode_script(script)
63
- encoded_script = script.encode('UTF-16LE', 'UTF-8')
64
- Base64.strict_encode64(encoded_script)
65
- end
66
-
67
- # suppress the progress stream from leaking to stderr
68
- def safe_script(script)
69
- "$ProgressPreference='SilentlyContinue';" + script
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,84 +0,0 @@
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_relative 'command_executor'
18
-
19
- module WinRM
20
- module FS
21
- module Core
22
- # Uploads the given source file to a temp file in 8k chunks
23
- class FileUploader
24
- def initialize(command_executor)
25
- @command_executor = command_executor
26
- end
27
-
28
- # Uploads the given file to the specified temp file as base64 encoded.
29
- #
30
- # @param [String] Path to the local source file on this machine
31
- # @param [String] Path to the file on the target machine
32
- # @return [Integer] Count of bytes uploaded
33
- def upload(local_file, remote_file, &block)
34
- @command_executor.run_powershell(prepare_script(remote_file))
35
- do_upload(local_file, dos_path(remote_file), &block)
36
- end
37
-
38
- private
39
-
40
- def do_upload(local_file, remote_file)
41
- bytes_copied = 0
42
- base64_array = base64_content(local_file)
43
- base64_array.each_slice(8000 - remote_file.size) do |chunk|
44
- @command_executor.run_cmd("echo #{chunk.join} >> \"#{remote_file}\"")
45
- bytes_copied += chunk.count
46
- yield bytes_copied, base64_array.count if block_given?
47
- end
48
- base64_array.length
49
- end
50
-
51
- def base64_content(local_file)
52
- base64_host_file = Base64.encode64(IO.binread(local_file)).gsub("\n", '')
53
- base64_host_file.chars.to_a
54
- end
55
-
56
- def dos_path(path)
57
- # TODO: convert all env vars
58
- path = path.gsub(/\$env:TEMP/, '%TEMP%')
59
- path.gsub(/\\/, '/')
60
- end
61
-
62
- # rubocop:disable Metrics/MethodLength
63
- def prepare_script(remote_file)
64
- <<-EOH
65
- $p = $ExecutionContext.SessionState.Path
66
- $path = $p.GetUnresolvedProviderPathFromPSPath("#{remote_file}")
67
-
68
- # if the file exists, truncate it
69
- if (Test-Path $path -PathType Leaf) {
70
- '' | Set-Content $path
71
- }
72
-
73
- # ensure the target directory exists
74
- $dir = [System.IO.Path]::GetDirectoryName($path)
75
- if (!(Test-Path $dir -PathType Container)) {
76
- mkdir $dir -ErrorAction SilentlyContinue | Out-Null
77
- }
78
- EOH
79
- end
80
- # rubocop:enable Metrics/MethodLength
81
- end
82
- end
83
- end
84
- end
@@ -1,187 +0,0 @@
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 'English'
18
- require 'zip'
19
- require 'fileutils'
20
- require 'pathname'
21
-
22
- module WinRM
23
- module FS
24
- module Core
25
- # Temporary zip file on the local system
26
- class TempZipFile
27
- attr_reader :zip_file, :path, :paths, :basedir, :options
28
-
29
- # Creates a new local temporary zip file
30
- # @param [String] Base directory to use when expanding out files passed to add
31
- # @param [Hash] Options: zip_file, via, recurse_paths
32
- def initialize(basedir = Dir.pwd, options = {})
33
- @basedir = Pathname.new(basedir)
34
- @options = options
35
- @zip_file = options[:zip_file] || Tempfile.new(['winrm_upload', '.zip'])
36
- @zip_file.close unless @zip_file.respond_to?('closed?') && @zip_file.closed?
37
- @path = Pathname.new(@zip_file)
38
- end
39
-
40
- # Adds a file or directory to the temporary zip file
41
- # @param [String] Directory or file path relative to basedir to add into zip
42
- def add(*new_paths)
43
- new_paths.each do | path |
44
- absolute_path = File.expand_path(path, basedir)
45
- fail "#{path} must exist relative to #{basedir}" unless File.exist? absolute_path
46
- paths << Pathname.new(absolute_path).relative_path_from(basedir)
47
- end
48
- end
49
-
50
- def paths
51
- @paths ||= []
52
- end
53
-
54
- def delete
55
- @zip_file.delete
56
- end
57
-
58
- def build
59
- factory.new(self).build
60
- end
61
-
62
- private
63
-
64
- def factory
65
- @factory ||= case options[:via]
66
- when nil, :rubyzip
67
- RubyZipFactory
68
- when :shell
69
- ShellZipFactory
70
- else
71
- fail "Unknown zip factory: #{factory}"
72
- end
73
- end
74
- end
75
-
76
- # Creates a zip file by shelling out to the zip command
77
- class ShellZipFactory
78
- attr_reader :zip_definition, :basedir, :zip_file, :paths, :options
79
-
80
- def initialize(zip_definition)
81
- @zip_definition = zip_definition
82
- @zip_file = zip_definition.zip_file
83
- @basedir = zip_definition.basedir
84
- @paths = zip_definition.paths
85
- @options = build_options.push('--names-stdin').join(' ')
86
- end
87
-
88
- def build
89
- Dir.chdir(basedir) do
90
- # zip doesn't like the file that already exists
91
- output = `zip #{zip_definition.path}.tmp #{options} < #{write_file_list.path}`
92
- fail "zip command failed: #{output}" unless $CHILD_STATUS.success?
93
-
94
- FileUtils.mv("#{zip_definition.path}.tmp", "#{zip_definition.path}")
95
- end
96
- end
97
-
98
- private
99
-
100
- def write_file_list
101
- file_list = Tempfile.new('file_list')
102
- file_list.puts paths.join("\n")
103
- file_list.close
104
- file_list
105
- end
106
-
107
- def build_options
108
- zip_definition.options.map do | key, value |
109
- prefix = key.length > 1 ? '--' : '-'
110
- if value == true
111
- "#{prefix}#{key}"
112
- else
113
- "#{prefix}#{key} #{value}"
114
- end
115
- end
116
- end
117
- end
118
-
119
- # Creates a zip file using RubyZip
120
- class RubyZipFactory
121
- attr_reader :zip_definition, :basedir
122
-
123
- def initialize(zip_definition)
124
- @zip_definition = zip_definition
125
- @basedir = zip_definition.basedir
126
- @zip = Zip::File.open(zip_definition.path, Zip::File::CREATE)
127
- end
128
-
129
- def build
130
- @zip_definition.paths.each do | path |
131
- absolute_path = File.expand_path(path, basedir)
132
- fail "#{path} doesn't exist" unless File.exist? absolute_path
133
-
134
- if File.directory?(absolute_path)
135
- add_directory(path)
136
- else
137
- add_file(path)
138
- end
139
- end
140
- close
141
- end
142
-
143
- def close
144
- @zip.close if @zip
145
- end
146
-
147
- private
148
-
149
- # Adds all files in the specified directory recursively into the zip file
150
- # @param [String] Directory to add into zip
151
- def add_directory(dir)
152
- glob_pattern = '*'
153
- glob_pattern = '**/*' if zip_definition.options[:recurse_paths]
154
-
155
- glob = File.join(basedir, dir, glob_pattern)
156
- Dir.glob(glob).each do |file|
157
- add_file(file)
158
- end
159
- end
160
-
161
- def add_file(file)
162
- write_zip_entry(file, basedir)
163
- end
164
-
165
- def write_zip_entry(file, _file_entry_path)
166
- absolute_file = File.expand_path(file, basedir)
167
- relative_file = Pathname.new(absolute_file).relative_path_from(basedir).to_s
168
- entry = new_zip_entry(relative_file)
169
- @zip.add(entry, absolute_file)
170
- end
171
-
172
- def new_zip_entry(file_entry_path)
173
- Zip::Entry.new(
174
- @zip,
175
- file_entry_path,
176
- nil,
177
- nil,
178
- nil,
179
- nil,
180
- nil,
181
- nil,
182
- ::Zip::DOSTime.new(2000))
183
- end
184
- end
185
- end
186
- end
187
- end