mirror of
https://github.com/hashicorp/vagrant.git
synced 2026-02-14 00:03:06 -05:00
Remove customized require behaviors and modify the bin executable to check for missing tools that Vagrant expects to exist when running outside of an installer.
239 lines
7.9 KiB
Ruby
239 lines
7.9 KiB
Ruby
# Copyright (c) HashiCorp, Inc.
|
|
# SPDX-License-Identifier: BUSL-1.1
|
|
|
|
require 'optparse'
|
|
require "rubygems/package"
|
|
|
|
module VagrantPlugins
|
|
module CommandUpload
|
|
class Command < Vagrant.plugin("2", :command)
|
|
|
|
VALID_COMPRESS_TYPES = [:tgz, :zip].freeze
|
|
|
|
def self.synopsis
|
|
"upload to machine via communicator"
|
|
end
|
|
|
|
def execute
|
|
options = {}
|
|
|
|
opts = OptionParser.new do |o|
|
|
o.banner = "Usage: vagrant upload [options] <source> [destination] [name|id]"
|
|
o.separator ""
|
|
o.separator "Options:"
|
|
o.separator ""
|
|
|
|
o.on("-t", "--temporary", "Upload source to temporary directory") do |t|
|
|
options[:temporary] = t
|
|
end
|
|
|
|
o.on("-c", "--compress", "Use gzip compression for upload") do |c|
|
|
options[:compress] = c
|
|
end
|
|
|
|
o.on("-C", "--compression-type=TYPE", "Type of compression to use (#{VALID_COMPRESS_TYPES.join(", ")})") do |c|
|
|
options[:compression_type] = c.to_sym
|
|
options[:compress] = true
|
|
end
|
|
end
|
|
|
|
argv = parse_options(opts)
|
|
return if !argv
|
|
|
|
case argv.size
|
|
when 3
|
|
source, destination, guest = argv
|
|
when 2, 1
|
|
source = argv[0]
|
|
if @env.active_machines.map(&:first).map(&:to_s).include?(argv[1])
|
|
guest = argv[1]
|
|
else
|
|
destination = argv[1]
|
|
end
|
|
else
|
|
raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp
|
|
end
|
|
|
|
# NOTE: We do this to handle paths on Windows like: "..\space dir\"
|
|
# because the final separator acts to escape the quote and ends up
|
|
# in the source value.
|
|
source = source.sub(/["']$/, "")
|
|
destination ||= File.basename(source)
|
|
|
|
if File.file?(source)
|
|
type = :file
|
|
elsif File.directory?(source)
|
|
type = :directory
|
|
else
|
|
raise Vagrant::Errors::UploadSourceMissing,
|
|
source: source
|
|
end
|
|
|
|
with_target_vms(guest, single_target: true) do |machine|
|
|
if options[:temporary]
|
|
if !machine.guest.capability?(:create_tmp_path)
|
|
raise Vagrant::Errors::UploadMissingTempCapability
|
|
end
|
|
extension = File.extname(source) if type == :file
|
|
destination = machine.guest.capability(:create_tmp_path, type: type, extension: extension)
|
|
end
|
|
|
|
if options[:compress]
|
|
compression_setup!(machine, options)
|
|
@env.ui.info(I18n.t("vagrant.commands.upload.compress",
|
|
source: source,
|
|
type: options[:compression_type]
|
|
))
|
|
destination_decompressed = destination
|
|
destination = machine.guest.capability(:create_tmp_path, type: :file, extension: ".#{options[:compression_type]}")
|
|
source_display = source
|
|
source = options[:compression_type] == :zip ? compress_source_zip(source) : compress_source_tgz(source)
|
|
end
|
|
|
|
@env.ui.info(I18n.t("vagrant.commands.upload.start",
|
|
source: source,
|
|
destination: destination
|
|
))
|
|
|
|
# If the source is a directory, attach a `/.` to the end so we
|
|
# upload the contents to the destination instead of within a
|
|
# folder at the destination
|
|
if File.directory?(source) && !source.end_with?(".")
|
|
upload_source = File.join(source, ".")
|
|
else
|
|
upload_source = source
|
|
end
|
|
|
|
machine.communicate.upload(upload_source, destination)
|
|
|
|
if options[:compress]
|
|
@env.ui.info(I18n.t("vagrant.commands.upload.decompress",
|
|
destination: destination_decompressed,
|
|
type: options[:compression_type]
|
|
))
|
|
machine.guest.capability(options[:decompression_method], destination, destination_decompressed, type: type)
|
|
destination = destination_decompressed
|
|
FileUtils.rm(source)
|
|
source = source_display
|
|
end
|
|
end
|
|
|
|
@env.ui.info(I18n.t("vagrant.commands.upload.complete",
|
|
source: source,
|
|
destination: destination
|
|
))
|
|
|
|
# Success, exit status 0
|
|
0
|
|
end
|
|
|
|
# Setup compression options and validate host and guest have capability
|
|
# to handle compression
|
|
#
|
|
# @param [Vagrant::Machine] machine Vagrant guest machine
|
|
# @param [Hash] options Command options
|
|
def compression_setup!(machine, options)
|
|
if !options[:compression_type]
|
|
if machine.guest.capability_host_chain.first[0] == :windows
|
|
options[:compression_type] = :zip
|
|
else
|
|
options[:compression_type] = :tgz
|
|
end
|
|
end
|
|
if !VALID_COMPRESS_TYPES.include?(options[:compression_type])
|
|
raise Vagrant::Errors::UploadInvalidCompressionType,
|
|
type: options[:compression_type],
|
|
valid_types: VALID_COMPRESS_TYPES.join(", ")
|
|
end
|
|
options[:decompression_method] = "decompress_#{options[:compression_type]}".to_sym
|
|
if !machine.guest.capability?(options[:decompression_method])
|
|
raise Vagrant::Errors::UploadMissingExtractCapability,
|
|
type: options[:compression_type]
|
|
end
|
|
end
|
|
|
|
# Compress path using zip into temporary file
|
|
#
|
|
# @param [String] path Path to compress
|
|
# @return [String] path to compressed file
|
|
def compress_source_zip(path)
|
|
require "zip"
|
|
zipfile = Tempfile.create(["vagrant", ".zip"])
|
|
zipfile.close
|
|
if File.file?(path)
|
|
source_items = [path]
|
|
else
|
|
source_items = Dir.glob(File.join(path, "**", "**", "*"))
|
|
end
|
|
c_dir = nil
|
|
Zip::File.open(zipfile.path, Zip::File::CREATE) do |zip|
|
|
source_items.each do |source_item|
|
|
next if File.directory?(source_item)
|
|
trim_item = source_item.sub(path, "").sub(%r{^[/\\]}, "")
|
|
dirname = File.dirname(trim_item)
|
|
zip.mkdir dirname if c_dir != dirname
|
|
c_dir = dirname
|
|
zip.get_output_stream(trim_item) do |f|
|
|
source_file = File.open(source_item, "rb")
|
|
while data = source_file.read(2048)
|
|
f.write(data)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
zipfile.path
|
|
end
|
|
|
|
# Compress path using tar and gzip into temporary file
|
|
#
|
|
# @param [String] path Path to compress
|
|
# @return [String] path to compressed file
|
|
def compress_source_tgz(path)
|
|
tarfile = Tempfile.create(["vagrant", ".tar"])
|
|
tarfile.close
|
|
tarfile = File.open(tarfile.path, "wb+")
|
|
tgzfile = Tempfile.create(["vagrant", ".tgz"])
|
|
tgzfile.close
|
|
tgzfile = File.open(tgzfile.path, "wb")
|
|
tar = Gem::Package::TarWriter.new(tarfile)
|
|
tgz = Zlib::GzipWriter.new(tgzfile)
|
|
if File.file?(path)
|
|
tar.add_file(File.basename(path), File.stat(path).mode) do |io|
|
|
File.open(path, "rb") do |file|
|
|
while bytes = file.read(4096)
|
|
io.write(bytes)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
Dir.glob(File.join(path, "**/**/*")).each do |item|
|
|
rel_path = item.sub(path, "")
|
|
item_mode = File.stat(item).mode
|
|
|
|
if File.directory?(item)
|
|
tar.mkdir(rel_path, item_mode)
|
|
else
|
|
tar.add_file(rel_path, item_mode) do |io|
|
|
File.open(item, "rb") do |file|
|
|
while bytes = file.read(4096)
|
|
io.write(bytes)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
tar.close
|
|
tarfile.rewind
|
|
while bytes = tarfile.read(4096)
|
|
tgz.write bytes
|
|
end
|
|
tgz.close
|
|
tgzfile.close
|
|
tarfile.close
|
|
File.delete(tarfile.path)
|
|
tgzfile.path
|
|
end
|
|
end
|
|
end
|
|
end
|