diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e019fac..e00b81738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ BUG FIXES: - core: Synced folders set to the default synced folder explicitly won't be deleted. [GH-2873] - core: Static IPs can end in ".1". A warning is now shown. [GH-2914] + - core: Adding boxes that have directories in them works on Windows. - commands/box: Box add `--force` works with `--provider` flag. [GH-2757] - commands/box: Listing boxes with machine-readable output crash is gone. - commands/plugin: Plugin installation will fail if dependencies conflict, diff --git a/lib/vagrant/box_collection.rb b/lib/vagrant/box_collection.rb index 62f942389..f25658fa8 100644 --- a/lib/vagrant/box_collection.rb +++ b/lib/vagrant/box_collection.rb @@ -166,13 +166,27 @@ module Vagrant # Move to final destination final_dir.mkpath - # Go through each child and copy them one-by-one. This avoids - # an issue where on Windows cross-device directory copies are - # failing for some reason. [GH-1424] - final_temp_dir.children(true).each do |f| - destination = final_dir.join(f.basename) - @logger.debug("Moving: #{f} => #{destination}") - FileUtils.mv(f, destination) + # Recursively move individual files from the temporary directory + # to the final location. We do this instead of moving the entire + # directory to avoid issues on Windows. [GH-1424] + copy_pairs = [[final_temp_dir, final_dir]] + while !copy_pairs.empty? + from, to = copy_pairs.shift + from.children(true).each do |f| + dest = to.join(f.basename) + + # We don't copy entire directories, so create the + # directory and then add to our list to copy. + if f.directory? + dest.mkpath + copy_pairs << [f, dest] + next + end + + # Copy the single file + @logger.debug("Moving: #{f} => #{dest}") + FileUtils.mv(f, dest) + end end if opts[:metadata_url]