winrm-fs 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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