Merge pull request #8939 from briancain/8933/master/source-path-file-prov
Align file provisioner functionality on all platforms
This commit is contained in:
commit
089117bc0f
|
@ -83,10 +83,23 @@ module VagrantPlugins
|
|||
raise_winrm_exception(e, "run_wql", query)
|
||||
end
|
||||
|
||||
# @param from [Array<String>, String] a single path or folder, or an
|
||||
# array of paths and folders to upload to the guest
|
||||
# @param to [String] a path or folder on the guest to upload to
|
||||
# @return [FixNum] Total size transfered from host to guest
|
||||
def upload(from, to)
|
||||
file_manager = WinRM::FS::FileManager.new(connection)
|
||||
if from.is_a?(Array)
|
||||
# Preserve return FixNum of bytes transfered
|
||||
return_bytes = 0
|
||||
from.each do |file|
|
||||
return_bytes += file_manager.upload(file, to)
|
||||
end
|
||||
return return_bytes
|
||||
else
|
||||
file_manager.upload(from, to)
|
||||
end
|
||||
end
|
||||
|
||||
def download(from, to)
|
||||
file_manager = WinRM::FS::FileManager.new(connection)
|
||||
|
|
|
@ -11,15 +11,28 @@ module VagrantPlugins
|
|||
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.
|
||||
# you will get nested folders
|
||||
#
|
||||
# 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 << "/."
|
||||
if !destination.end_with?(File::SEPARATOR) &&
|
||||
!source.end_with?("#{File::SEPARATOR}.")
|
||||
# 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
|
||||
#
|
||||
# If source is set as `source/` it will lose the trailing
|
||||
# slash due to how `File.expand_path` works, so we don't need
|
||||
# a conditional for that case.
|
||||
if @machine.config.vm.communicator == :winrm
|
||||
# windows needs an array of paths because of the
|
||||
# winrm-fs function Vagrant is using to upload file/folder.
|
||||
source = Dir["#{source}#{File::SEPARATOR}*"]
|
||||
else
|
||||
source << "#{File::SEPARATOR}."
|
||||
end
|
||||
end
|
||||
else
|
||||
command = "mkdir -p \"%s\"" % File.dirname(destination)
|
||||
end
|
||||
|
|
|
@ -31,6 +31,35 @@ describe VagrantPlugins::CommunicatorWinRM::WinRMShell do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#upload" do
|
||||
let(:fm) { double("file_manager") }
|
||||
it "should call file_manager.upload for each passed in path" do
|
||||
from = ["/path", "/path/folder", "/path/folder/file.py"]
|
||||
to = "/destination"
|
||||
size = 80
|
||||
|
||||
allow(WinRM::FS::FileManager).to receive(:new).with(connection)
|
||||
.and_return(fm)
|
||||
allow(fm).to receive(:upload).and_return(size)
|
||||
|
||||
expect(fm).to receive(:upload).exactly(from.size).times
|
||||
expect(subject.upload(from, to)).to eq(size*from.size)
|
||||
end
|
||||
|
||||
it "should call file_manager.upload once for a single path" do
|
||||
from = "/path/folder/file.py"
|
||||
to = "/destination"
|
||||
size = 80
|
||||
|
||||
allow(WinRM::FS::FileManager).to receive(:new).with(connection)
|
||||
.and_return(fm)
|
||||
allow(fm).to receive(:upload).and_return(size)
|
||||
|
||||
expect(fm).to receive(:upload).exactly(1).times
|
||||
expect(subject.upload(from, to)).to eq(size)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".powershell" do
|
||||
it "should call winrm powershell" do
|
||||
expect(shell).to receive(:run).with("dir").and_return(output)
|
||||
|
|
|
@ -89,5 +89,39 @@ describe VagrantPlugins::FileUpload::Provisioner do
|
|||
|
||||
subject.provision
|
||||
end
|
||||
|
||||
it "appends a '/.' if the destination doesnt end with a file separator" do
|
||||
allow(config).to receive(:source).and_return("/source")
|
||||
allow(config).to receive(:destination).and_return("/foo/bar")
|
||||
allow(File).to receive(:directory?).with("/source").and_return(true)
|
||||
|
||||
expect(guest).to receive(:capability?).
|
||||
with(:shell_expand_guest_path).and_return(true)
|
||||
expect(guest).to receive(:capability).
|
||||
with(:shell_expand_guest_path, "/foo/bar").and_return("/foo/bar")
|
||||
|
||||
expect(communicator).to receive(:upload).with("/source/.", "/foo/bar")
|
||||
|
||||
subject.provision
|
||||
end
|
||||
|
||||
it "sends an array of files and folders if winrm and destination doesn't end with file separator" do
|
||||
files = ["/source/file.py", "/source/folder"]
|
||||
allow(Dir).to receive(:[]).and_return(files)
|
||||
allow(config).to receive(:source).and_return("/source")
|
||||
allow(config).to receive(:destination).and_return("/foo/bar")
|
||||
allow(File).to receive(:directory?).with("/source").and_return(true)
|
||||
allow(machine.config.vm).to receive(:communicator).and_return(:winrm)
|
||||
|
||||
expect(guest).to receive(:capability?).
|
||||
with(:shell_expand_guest_path).and_return(true)
|
||||
expect(guest).to receive(:capability).
|
||||
with(:shell_expand_guest_path, "/foo/bar").and_return("/foo/bar")
|
||||
|
||||
expect(communicator).to receive(:upload)
|
||||
.with(files, "/foo/bar")
|
||||
|
||||
subject.provision
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,6 +25,42 @@ new VM.
|
|||
config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
|
||||
end
|
||||
|
||||
If you want to upload a folder to your guest system, it can be accomplished by
|
||||
using a file provisioner seen below. When copied, the resulting folder on the guest will
|
||||
replace `folder` as `newfolder` and place its on the guest machine. Note that if
|
||||
you'd like the same folder name on your guest machine, make sure that the destination
|
||||
path has the same name as the folder on your host.
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
# ... other configuration
|
||||
|
||||
config.vm.provision "file", source: "~/path/to/host/folder", destination: "$HOME/remote/newfolder"
|
||||
end
|
||||
|
||||
Prior to copying `~/path/to/host/folder` to the guest machine:
|
||||
|
||||
folder
|
||||
├── script.sh
|
||||
├── otherfolder
|
||||
│ └── hello.sh
|
||||
├── goodbye.sh
|
||||
├── hello.sh
|
||||
└── woot.sh
|
||||
|
||||
1 directory, 5 files
|
||||
|
||||
After to copying `~/path/to/host/folder` into `$HOME/remote/newfolder` to the guest machine:
|
||||
|
||||
newfolder
|
||||
├── script.sh
|
||||
├── otherfolder
|
||||
│ └── hello.sh
|
||||
├── goodbye.sh
|
||||
├── hello.sh
|
||||
└── woot.sh
|
||||
|
||||
1 directory, 5 files
|
||||
|
||||
Note that, unlike with synced folders, files or directories that are uploaded
|
||||
will not be kept in sync. Continuing with the example above, if you make
|
||||
further changes to your local ~/.gitconfig, they will not be immediately
|
||||
|
@ -49,3 +85,36 @@ The file provisioner takes only two options, both of which are required:
|
|||
the source will be uploaded to. The file/folder is uploaded as the SSH user
|
||||
over SCP, so this location must be writable to that user. The SSH user can be
|
||||
determined by running `vagrant ssh-config`, and defaults to "vagrant".
|
||||
|
||||
## Caveats
|
||||
|
||||
While the file provisioner does support trailing slashes or "globing", this can
|
||||
lead to some confusing results due to the underlying tool used to copy files and
|
||||
folders between the host and guests. For example, if you have a source and
|
||||
destination with a trailing slash defined below:
|
||||
|
||||
config.vm.provision "file", source: "~/pathfolder", destination: "/remote/newlocation/"
|
||||
|
||||
You are telling vagrant to upload `~/pathfolder` under the remote dir `/remote/newlocation`,
|
||||
which will look like:
|
||||
|
||||
newlocation
|
||||
├── pathfolder
|
||||
│ └── file.sh
|
||||
|
||||
1 directory, 2 files
|
||||
|
||||
This behavior can also be achieved by defining your file provisioner below:
|
||||
|
||||
config.vm.provision "file", source: "~/pathfolder", destination: "/remote/newlocation/pathfolder"
|
||||
|
||||
Another example is using globing on the host machine to grab all files within a
|
||||
folder, but not the top level folder itself:
|
||||
|
||||
config.vm.provision "file", source: "~/otherfolder/.", destination: "/remote/otherlocation"
|
||||
|
||||
The file provisioner is defined to include all files under `~/otherfolder`
|
||||
to the new location `/remote/otherlocation`. This idea can be achieved by simply
|
||||
having your destination folder differ from the source folder:
|
||||
|
||||
config.vm.provision "file", source: "/otherfolder", destination: "/remote/otherlocation"
|
||||
|
|
Loading…
Reference in New Issue