diff --git a/plugins/guests/darwin/cap/shell_expand_guest_path.rb b/plugins/guests/darwin/cap/shell_expand_guest_path.rb index 1fdcf5215..22c7bd11a 100644 --- a/plugins/guests/darwin/cap/shell_expand_guest_path.rb +++ b/plugins/guests/darwin/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}") do |type, data| + machine.communicate.execute("printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data @@ -14,7 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/freebsd/cap/shell_expand_guest_path.rb b/plugins/guests/freebsd/cap/shell_expand_guest_path.rb index 6d2f6e16a..14ae7184d 100644 --- a/plugins/guests/freebsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/freebsd/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}", + machine.communicate.execute("printf \"#{path}\"", shell: "sh") do |type, data| if type == :stdout real_path ||= "" @@ -15,7 +15,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/linux/cap/shell_expand_guest_path.rb b/plugins/guests/linux/cap/shell_expand_guest_path.rb index cc32d7f7c..653068a78 100644 --- a/plugins/guests/linux/cap/shell_expand_guest_path.rb +++ b/plugins/guests/linux/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("echo; printf #{path}") do |type, data| + machine.communicate.execute("echo; printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data @@ -19,7 +19,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/netbsd/cap/shell_expand_guest_path.rb b/plugins/guests/netbsd/cap/shell_expand_guest_path.rb index 8471f4724..007c5f944 100644 --- a/plugins/guests/netbsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/netbsd/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}") do |type, data| + machine.communicate.execute("printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data @@ -14,7 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/guests/openbsd/cap/shell_expand_guest_path.rb b/plugins/guests/openbsd/cap/shell_expand_guest_path.rb index 653493548..2a4f8b5ed 100644 --- a/plugins/guests/openbsd/cap/shell_expand_guest_path.rb +++ b/plugins/guests/openbsd/cap/shell_expand_guest_path.rb @@ -4,7 +4,7 @@ module VagrantPlugins class ShellExpandGuestPath def self.shell_expand_guest_path(machine, path) real_path = nil - machine.communicate.execute("printf #{path}") do |type, data| + machine.communicate.execute("printf \"#{path}\"") do |type, data| if type == :stdout real_path ||= "" real_path += data @@ -14,7 +14,7 @@ module VagrantPlugins if !real_path # If no real guest path was detected, this is really strange # and we raise an exception because this is a bug. - raise ShellExpandFailed + raise Vagrant::Errors::ShellExpandFailed end # Chomp the string so that any trailing newlines are killed diff --git a/plugins/provisioners/file/provisioner.rb b/plugins/provisioners/file/provisioner.rb index 7b997a7dc..46355c11b 100644 --- a/plugins/provisioners/file/provisioner.rb +++ b/plugins/provisioners/file/provisioner.rb @@ -3,14 +3,30 @@ module VagrantPlugins class Provisioner < Vagrant.plugin("2", :provisioner) def provision @machine.communicate.tap do |comm| + source = File.expand_path(config.source) destination = expand_guest_path(config.destination) + # if source is a directory, make it then trim destination with dirname # Make sure the remote path exists - command = "mkdir -p %s" % File.dirname(destination) + if File.directory?(source) + # We need to make sure the actual destination folder + # also exists before uploading, otherwise + # you will get nested folders. We also need to append + # a './' to the source folder so we copy the contents + # rather than the folder itself, in case a users destination + # folder differs from its source. + # + # https://serverfault.com/questions/538368/make-scp-always-overwrite-or-create-directory + # https://unix.stackexchange.com/questions/292641/get-scp-path-behave-like-rsync-path/292732 + command = "mkdir -p \"%s\"" % destination + source << "/." + else + command = "mkdir -p \"%s\"" % File.dirname(destination) + end comm.execute(command) # now upload the file - comm.upload(File.expand_path(config.source), destination) + comm.upload(source, destination) end end diff --git a/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..fbbc45588 --- /dev/null +++ b/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestDarwin::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestDarwin::Plugin + .components + .guest_capabilities[:darwin] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..2f10f8663 --- /dev/null +++ b/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,44 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestFreeBSD::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestFreeBSD::Plugin + .components + .guest_capabilities[:freebsd] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute) + .with("printf \"#{path}\"", {:shell=>"sh"}) + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..0caf4ae1d --- /dev/null +++ b/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestLinux::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestLinux::Plugin + .components + .guest_capabilities[:linux] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("echo; printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..49e4e6305 --- /dev/null +++ b/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestNetBSD::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestNetBSD::Plugin + .components + .guest_capabilities[:netbsd] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb b/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb new file mode 100644 index 000000000..1cd787911 --- /dev/null +++ b/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb @@ -0,0 +1,43 @@ +require_relative "../../../../base" + +describe "VagrantPlugins::GuestOpenBSD::Cap::ShellExpandGuestPath" do + let(:caps) do + VagrantPlugins::GuestOpenBSD::Plugin + .components + .guest_capabilities[:openbsd] + end + + let(:machine) { double("machine") } + let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) } + + before do + allow(machine).to receive(:communicate).and_return(comm) + end + + describe "#shell_expand_guest_path" do + let(:cap) { caps.get(:shell_expand_guest_path) } + + it "expands the path" do + path = "/home/vagrant/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant/folder") + + cap.shell_expand_guest_path(machine, path) + end + + it "raises an exception if no path was detected" do + path = "/home/vagrant/folder" + expect { cap.shell_expand_guest_path(machine, path) }. + to raise_error(Vagrant::Errors::ShellExpandFailed) + end + + it "returns a path with a space in it" do + path = "/home/vagrant folder/folder" + allow(machine.communicate).to receive(:execute). + with(any_args).and_yield(:stdout, "/home/vagrant folder/folder") + + expect(machine.communicate).to receive(:execute).with("printf \"#{path}\"") + cap.shell_expand_guest_path(machine, path) + end + end +end diff --git a/test/unit/plugins/provisioners/file/provisioner_test.rb b/test/unit/plugins/provisioners/file/provisioner_test.rb index a42f1169c..8da38e6d7 100644 --- a/test/unit/plugins/provisioners/file/provisioner_test.rb +++ b/test/unit/plugins/provisioners/file/provisioner_test.rb @@ -34,7 +34,25 @@ describe VagrantPlugins::FileUpload::Provisioner do allow(config).to receive(:source).and_return("/source") allow(config).to receive(:destination).and_return("/foo/bar") - expect(communicator).to receive(:execute).with("mkdir -p /foo") + expect(communicator).to receive(:execute).with("mkdir -p \"/foo\"") + + subject.provision + end + + it "creates the destination directory with a space" do + allow(config).to receive(:source).and_return("/source") + allow(config).to receive(:destination).and_return("/foo bar/bar") + + expect(communicator).to receive(:execute).with("mkdir -p \"/foo bar\"") + + subject.provision + end + + it "creates the destination directory above file" do + allow(config).to receive(:source).and_return("/source/file.sh") + allow(config).to receive(:destination).and_return("/foo/bar/file.sh") + + expect(communicator).to receive(:execute).with("mkdir -p \"/foo/bar\"") subject.provision end