lib/vagrant-winrm/commands/winrm_upload.rb in vagrant-winrm-0.0.2 vs lib/vagrant-winrm/commands/winrm_upload.rb in vagrant-winrm-0.4.0

- old
+ new

@@ -6,35 +6,106 @@ def self.synopsis 'upload file or directory to machine via WinRM' end def execute + options = { temporary: false, compress: false } + source, destination, argv = parse_args options + return unless source || destination + + # Execute the actual WinRM + with_target_vms(argv, single_target: true) do |vm| + + raise Errors::ConfigurationError, { :communicator => vm.config.vm.communicator } if vm.config.vm.communicator != :winrm + + tmp_dest = get_remote_temp_folder(vm) if options[:temporary] || options[:compress] + + dest_file = options[:temporary] ? ::File.join(tmp_dest, destination) : destination + $stdout.print dest_file if options[:temporary] + + @logger.debug("Uploading #{source} to #{destination}") + if options[:compress] + source_is_dir = ::File.directory? source + source = compress(source, source_is_dir) + + dest_dir = source_is_dir || dest_file.end_with?('/') || dest_file.end_with?('\\') ? dest_file : ::File.dirname(dest_file) + remote_tgz_path = ::File.join(::File.dirname(tmp_dest), ::File.basename(source)) + vm.communicate.upload(source, remote_tgz_path) + return vm.communicate.execute("New-Item '#{dest_dir}' -type directory -force; tar -xzf '#{remote_tgz_path}' -C '#{dest_dir}'; ") + else + return vm.communicate.upload(source, dest_file) + end + end + end + + + private + + def compress(source, source_is_dir) + require 'zlib' + require 'tempfile' + require 'archive/tar/minitar' + + cwd = Dir.pwd + begin + tmp = ::Tempfile.new(['script', '.tar.gz']) + tmp.binmode + tgz = Zlib::GzipWriter.new (tmp) + + Dir.chdir source_is_dir ? source : ::File.dirname(source) + Archive::Tar::Minitar.pack(source_is_dir ? '.' : ::File.basename(source), tgz) + + tmp.path # returns the temporary file path + ensure + tgz.close if tgz && !tgz.closed? + tmp.close if tmp && !tmp.closed? + Dir.chdir cwd + end + end + + def parse_args(options) opts = OptionParser.new do |o| - o.banner = 'Usage: vagrant winrm-upload <source> <destination> [name]' + o.banner = <<-EOS +Usage: +\tvagrant winrm-upload [-c] <source> <destination> [name] +\tvagrant winrm-upload [-c] -t <source> [name] + EOS + o.separator 'Options:' + + o.on('-t', '--temporary', 'Upload the source file to a temporary directory and return the path') do + options[:temporary] = true + end + + o.on('-c', '--compress', 'Use gzip compression to speed up the upload') do + options[:compress] = true + end end # Parse the options and return if we don't have any target. argv = parse_options opts return unless argv - if argv.empty? || argv.length > 3 || argv.length < 2 - raise Vagrant::Errors::CLIInvalidUsage, - help: opts.help.chomp + source = argv[0] + if options[:temporary] + min, max, destination = 1, 2, ::File.basename(argv[0]) + else + min, max, destination = 2, 3, argv[1] end - source = argv[0] - destination = argv[1] - argv = argv.drop(2) + if argv.empty? || argv.length > max || argv.length < min + raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp + end + [source, destination, argv.drop(min)] + end - # Execute the actual WinRM - with_target_vms(argv, single_target: true) do |vm| - - raise Errors::ConfigurationError, { :communicator => vm.config.vm.communicator } if vm.config.vm.communicator != :winrm - - @logger.debug("Uploading #{source} to #{destination}") - return vm.communicate.upload(source, destination) + def get_remote_temp_folder(vm) + dir = nil + vm.communicate.execute('[System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) | Write-Host -NoNewline') do |type, data| + raise Errors::TempFolderError, { :communicator => vm.config.vm.communicator } if type == :stderr || dir + dir = data end + dir end end end end