vagrant-reflect 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/vagrant-reflect/command/reflect.rb +51 -38
 - data/lib/vagrant-reflect/configuration/reflect.rb +25 -0
 - data/lib/vagrant-reflect/patched/subprocess.rb +3 -0
 - data/lib/vagrant-reflect/plugin.rb +5 -0
 - data/lib/vagrant-reflect/util/excludes.rb +53 -0
 - data/lib/vagrant-reflect/util/reflector.rb +82 -0
 - data/lib/vagrant-reflect/util/shell.rb +136 -0
 - data/lib/vagrant-reflect/util/sync.rb +146 -0
 - data/lib/vagrant-reflect/version.rb +1 -1
 - metadata +7 -3
 - data/lib/vagrant-reflect/util/syncer.rb +0 -327
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: e84bae9f41ff115636ac176da7601c803d83389d
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 627b6a9da251a1da3998de39a25b6fd82564b9a2
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 4b852921fb6bce29d04984873f0a543e8982f1ca0fdc4521cbaddd7957c3f5351d55f8515a34e2d44511aeb9ed1262cf3707fbb64fe5d1f291194f21d8bab839
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: adb7c4d480eb25fd9288bf9db0b7bb23fe6bb249779262ab3570010b0ec7186ca01d2fa7942225f4e02b84740e77f71b223cb51ccb1e40eb4f152bb762f82f15
         
     | 
| 
         @@ -1,12 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'log4r'
         
     | 
| 
       2 
2 
     | 
    
         
             
            require 'optparse'
         
     | 
| 
       3 
3 
     | 
    
         
             
            require 'thread'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'date'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            require 'vagrant/action/builtin/mixin_synced_folders'
         
     | 
| 
       6 
7 
     | 
    
         
             
            require 'vagrant/util/busy'
         
     | 
| 
       7 
8 
     | 
    
         
             
            require 'vagrant/util/platform'
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            require_relative '../util/ 
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative '../util/excludes'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative '../util/sync'
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
            require 'driskell-listen'
         
     | 
| 
       12 
14 
     | 
    
         | 
| 
         @@ -26,21 +28,9 @@ module VagrantReflect 
     | 
|
| 
       26 
28 
     | 
    
         
             
                      poll:        false,
         
     | 
| 
       27 
29 
     | 
    
         
             
                      incremental: true
         
     | 
| 
       28 
30 
     | 
    
         
             
                    }
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       29 
32 
     | 
    
         
             
                    opts = OptionParser.new do |o|
         
     | 
| 
       30 
33 
     | 
    
         
             
                      o.banner = 'Usage: vagrant reflect [vm-name]'
         
     | 
| 
       31 
     | 
    
         
            -
                      o.separator ''
         
     | 
| 
       32 
     | 
    
         
            -
                      o.separator 'Options:'
         
     | 
| 
       33 
     | 
    
         
            -
                      o.separator ''
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                      o.on('--[no-]poll', 'Force polling filesystem (slow)') do |poll|
         
     | 
| 
       36 
     | 
    
         
            -
                        options[:poll] = poll
         
     | 
| 
       37 
     | 
    
         
            -
                      end
         
     | 
| 
       38 
     | 
    
         
            -
                      o.on(
         
     | 
| 
       39 
     | 
    
         
            -
                        '--[no-]incremental',
         
     | 
| 
       40 
     | 
    
         
            -
                        'Perform incremental copies of changes where possible (fast)'
         
     | 
| 
       41 
     | 
    
         
            -
                      ) do |incremental|
         
     | 
| 
       42 
     | 
    
         
            -
                        options[:incremental] = incremental
         
     | 
| 
       43 
     | 
    
         
            -
                      end
         
     | 
| 
       44 
34 
     | 
    
         
             
                    end
         
     | 
| 
       45 
35 
     | 
    
         | 
| 
       46 
36 
     | 
    
         
             
                    # Parse the options and return if we don't have any target.
         
     | 
| 
         @@ -50,28 +40,8 @@ module VagrantReflect 
     | 
|
| 
       50 
40 
     | 
    
         
             
                    # Build up the paths that we need to listen to.
         
     | 
| 
       51 
41 
     | 
    
         
             
                    paths = {}
         
     | 
| 
       52 
42 
     | 
    
         
             
                    with_target_vms(argv) do |machine|
         
     | 
| 
       53 
     | 
    
         
            -
                       
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                        if proxy
         
     | 
| 
       56 
     | 
    
         
            -
                          machine.ui.warn(
         
     | 
| 
       57 
     | 
    
         
            -
                            I18n.t(
         
     | 
| 
       58 
     | 
    
         
            -
                              'vagrant.plugins.vagrant-reflect.rsync_proxy_machine',
         
     | 
| 
       59 
     | 
    
         
            -
                              name: machine.name.to_s,
         
     | 
| 
       60 
     | 
    
         
            -
                              provider: machine.provider_name.to_s))
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                          machine = proxy
         
     | 
| 
       63 
     | 
    
         
            -
                        end
         
     | 
| 
       64 
     | 
    
         
            -
                      end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                      cached = synced_folders(machine, cached: true)
         
     | 
| 
       67 
     | 
    
         
            -
                      fresh  = synced_folders(machine)
         
     | 
| 
       68 
     | 
    
         
            -
                      diff   = synced_folders_diff(cached, fresh)
         
     | 
| 
       69 
     | 
    
         
            -
                      unless diff[:added].empty?
         
     | 
| 
       70 
     | 
    
         
            -
                        machine.ui.warn(
         
     | 
| 
       71 
     | 
    
         
            -
                          I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_new_folders'))
         
     | 
| 
       72 
     | 
    
         
            -
                      end
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                      folders = cached[:rsync]
         
     | 
| 
      
 43 
     | 
    
         
            +
                      machine = check_proxy(machine)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      folders = get_folders(machine)
         
     | 
| 
       75 
45 
     | 
    
         
             
                      next if !folders || folders.empty?
         
     | 
| 
       76 
46 
     | 
    
         | 
| 
       77 
47 
     | 
    
         
             
                      folders.each do |id, folder_opts|
         
     | 
| 
         @@ -84,7 +54,7 @@ module VagrantReflect 
     | 
|
| 
       84 
54 
     | 
    
         
             
                        folder_opts[:exclude] ||= []
         
     | 
| 
       85 
55 
     | 
    
         
             
                        folder_opts[:exclude] << '.vagrant/'
         
     | 
| 
       86 
56 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
                        syncer =  
     | 
| 
      
 57 
     | 
    
         
            +
                        syncer = Util::Sync.new(machine, folder_opts)
         
     | 
| 
       88 
58 
     | 
    
         | 
| 
       89 
59 
     | 
    
         
             
                        machine.ui.info(
         
     | 
| 
       90 
60 
     | 
    
         
             
                          I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_initial'))
         
     | 
| 
         @@ -120,7 +90,7 @@ module VagrantReflect 
     | 
|
| 
       120 
90 
     | 
    
         | 
| 
       121 
91 
     | 
    
         
             
                      ignores = []
         
     | 
| 
       122 
92 
     | 
    
         
             
                      opts.each do |path_opts|
         
     | 
| 
       123 
     | 
    
         
            -
                        ignores += path_opts[: 
     | 
| 
      
 93 
     | 
    
         
            +
                        ignores += Util::Excludes.convert(path_opts[:opts][:excludes] || [])
         
     | 
| 
       124 
94 
     | 
    
         
             
                        path_opts[:machine].ui.info(
         
     | 
| 
       125 
95 
     | 
    
         
             
                          I18n.t(
         
     | 
| 
       126 
96 
     | 
    
         
             
                            'vagrant.plugins.vagrant-reflect.rsync_auto_path',
         
     | 
| 
         @@ -158,6 +128,33 @@ module VagrantReflect 
     | 
|
| 
       158 
128 
     | 
    
         
             
                    0
         
     | 
| 
       159 
129 
     | 
    
         
             
                  end
         
     | 
| 
       160 
130 
     | 
    
         | 
| 
      
 131 
     | 
    
         
            +
                  def check_proxy(machine)
         
     | 
| 
      
 132 
     | 
    
         
            +
                    return machine unless machine.provider.capability?(:proxy_machine)
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    proxy = machine.provider.capability(:proxy_machine)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    return machine unless proxy
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                    machine.ui.warn(
         
     | 
| 
      
 138 
     | 
    
         
            +
                      I18n.t(
         
     | 
| 
      
 139 
     | 
    
         
            +
                        'vagrant.plugins.vagrant-reflect.rsync_proxy_machine',
         
     | 
| 
      
 140 
     | 
    
         
            +
                        name: machine.name.to_s,
         
     | 
| 
      
 141 
     | 
    
         
            +
                        provider: machine.provider_name.to_s))
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                    proxy
         
     | 
| 
      
 144 
     | 
    
         
            +
                  end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  def get_folders(machine)
         
     | 
| 
      
 147 
     | 
    
         
            +
                    cached = synced_folders(machine, cached: true)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    fresh  = synced_folders(machine)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    diff   = synced_folders_diff(cached, fresh)
         
     | 
| 
      
 150 
     | 
    
         
            +
                    unless diff[:added].empty?
         
     | 
| 
      
 151 
     | 
    
         
            +
                      machine.ui.warn(
         
     | 
| 
      
 152 
     | 
    
         
            +
                        I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_new_folders'))
         
     | 
| 
      
 153 
     | 
    
         
            +
                    end
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                    cached[:rsync]
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
       161 
158 
     | 
    
         
             
                  # This is the callback that is called when any changes happen
         
     | 
| 
       162 
159 
     | 
    
         
             
                  def callback(path, opts, options, modified, added, removed)
         
     | 
| 
       163 
160 
     | 
    
         
             
                    @logger.info("File change callback called for #{path}!")
         
     | 
| 
         @@ -174,6 +171,7 @@ module VagrantReflect 
     | 
|
| 
       174 
171 
     | 
    
         
             
                        send callback, path, path_opts, modified, added, removed
         
     | 
| 
       175 
172 
     | 
    
         | 
| 
       176 
173 
     | 
    
         
             
                        path_opts[:machine].ui.info(
         
     | 
| 
      
 174 
     | 
    
         
            +
                          get_sync_time +
         
     | 
| 
       177 
175 
     | 
    
         
             
                          I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_synced'))
         
     | 
| 
       178 
176 
     | 
    
         
             
                      rescue Vagrant::Errors::MachineGuestNotReady
         
     | 
| 
       179 
177 
     | 
    
         
             
                        # Error communicating to the machine, probably a reload or
         
     | 
| 
         @@ -209,12 +207,15 @@ module VagrantReflect 
     | 
|
| 
       209 
207 
     | 
    
         
             
                  end
         
     | 
| 
       210 
208 
     | 
    
         | 
| 
       211 
209 
     | 
    
         
             
                  def sync_incremental(path, path_opts, modified, added, removed)
         
     | 
| 
      
 210 
     | 
    
         
            +
                    sync_time = get_sync_time
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
       212 
212 
     | 
    
         
             
                    if !modified.empty? || !added.empty?
         
     | 
| 
       213 
213 
     | 
    
         
             
                      # Pass the list of changes to rsync so we quickly synchronise only
         
     | 
| 
       214 
214 
     | 
    
         
             
                      # the changed files instead of the whole folder
         
     | 
| 
       215 
215 
     | 
    
         
             
                      items = strip_paths(path, modified + added)
         
     | 
| 
       216 
216 
     | 
    
         
             
                      path_opts[:syncer].sync_incremental(items) do |item|
         
     | 
| 
       217 
217 
     | 
    
         
             
                        path_opts[:machine].ui.info(
         
     | 
| 
      
 218 
     | 
    
         
            +
                          sync_time +
         
     | 
| 
       218 
219 
     | 
    
         
             
                          I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_increment_change',
         
     | 
| 
       219 
220 
     | 
    
         
             
                                 path: item))
         
     | 
| 
       220 
221 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -226,11 +227,23 @@ module VagrantReflect 
     | 
|
| 
       226 
227 
     | 
    
         
             
                    items = strip_paths(path, removed)
         
     | 
| 
       227 
228 
     | 
    
         
             
                    path_opts[:syncer].sync_removals(items) do |item|
         
     | 
| 
       228 
229 
     | 
    
         
             
                      path_opts[:machine].ui.info(
         
     | 
| 
      
 230 
     | 
    
         
            +
                        sync_time +
         
     | 
| 
       229 
231 
     | 
    
         
             
                        I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_increment_remove',
         
     | 
| 
       230 
232 
     | 
    
         
             
                               path: item))
         
     | 
| 
       231 
233 
     | 
    
         
             
                    end
         
     | 
| 
       232 
234 
     | 
    
         
             
                  end
         
     | 
| 
       233 
235 
     | 
    
         | 
| 
      
 236 
     | 
    
         
            +
                  def get_sync_time()
         
     | 
| 
      
 237 
     | 
    
         
            +
                    # TODO: Hold this configuration per machine when we refactor
         
     | 
| 
      
 238 
     | 
    
         
            +
                    with_target_vms(nil, single_target: true) do |vm|
         
     | 
| 
      
 239 
     | 
    
         
            +
                      if vm.config.reflect.show_sync_time == true
         
     | 
| 
      
 240 
     | 
    
         
            +
                        return '(' + Time.now.strftime("%H:%M:%S") + ') '
         
     | 
| 
      
 241 
     | 
    
         
            +
                      end
         
     | 
| 
      
 242 
     | 
    
         
            +
                    end
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                    ''
         
     | 
| 
      
 245 
     | 
    
         
            +
                  end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
       234 
247 
     | 
    
         
             
                  def strip_paths(path, items)
         
     | 
| 
       235 
248 
     | 
    
         
             
                    items.map do |item|
         
     | 
| 
       236 
249 
     | 
    
         
             
                      item[path.length..-1]
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module VagrantReflect
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Configuration
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Configuration object for vagrant-reflect
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Reflect < Vagrant.plugin('2', :config)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  attr_accessor :show_sync_time
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @show_sync_time = UNSET_VALUE
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def finalize!
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @show_sync_time = 0 if @show_sync_time == UNSET_VALUE
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def validate(_)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    errors = _detected_errors
         
     | 
| 
      
 17 
     | 
    
         
            +
                    if show_sync_time != true && show_sync_time != false
         
     | 
| 
      
 18 
     | 
    
         
            +
                      errors << 'show_sync_time must be TRUE or FALSE'
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    { 'reflect' => errors }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module VagrantReflect
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Util
         
     | 
| 
      
 3 
     | 
    
         
            +
                # This is a helper that builds the required commands and returns them
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Excludes
         
     | 
| 
      
 5 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                    PATTERNS = [
         
     | 
| 
      
 7 
     | 
    
         
            +
                      ['.', '\\.'],
         
     | 
| 
      
 8 
     | 
    
         
            +
                      ['***', '|||EMPTY|||'],
         
     | 
| 
      
 9 
     | 
    
         
            +
                      ['**', '|||GLOBAL|||'],
         
     | 
| 
      
 10 
     | 
    
         
            +
                      ['*', '|||PATH|||'],
         
     | 
| 
      
 11 
     | 
    
         
            +
                      ['?', '[^/]'],
         
     | 
| 
      
 12 
     | 
    
         
            +
                      ['|||PATH|||', '[^/]+'],
         
     | 
| 
      
 13 
     | 
    
         
            +
                      ['|||GLOBAL|||', '.+'],
         
     | 
| 
      
 14 
     | 
    
         
            +
                      ['|||EMPTY|||', '.*']
         
     | 
| 
      
 15 
     | 
    
         
            +
                    ].freeze
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    # This converts the rsync exclude patterns to regular expressions we can
         
     | 
| 
      
 18 
     | 
    
         
            +
                    # send to Listen.
         
     | 
| 
      
 19 
     | 
    
         
            +
                    def convert(excludes)
         
     | 
| 
      
 20 
     | 
    
         
            +
                      excludes.map(&method(:convert_single))
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    protected
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    def convert_single(exclude)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      start_anchor = false
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                      if exclude.start_with?('/')
         
     | 
| 
      
 29 
     | 
    
         
            +
                        start_anchor = true
         
     | 
| 
      
 30 
     | 
    
         
            +
                        exclude = exclude[1..-1]
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      regexp = start_anchor ? '^' : '(?:^|/)'
         
     | 
| 
      
 34 
     | 
    
         
            +
                      regexp += perform_substitutions(exclude)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      regexp += exclude.end_with?('/') ? '' : '(?:/|$)'
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                      Regexp.new(regexp)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    def perform_substitutions(exclude)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      # This is REALLY ghetto, but its a start. We can improve and
         
     | 
| 
      
 42 
     | 
    
         
            +
                      # keep unit tests passing in the future.
         
     | 
| 
      
 43 
     | 
    
         
            +
                      # TODO: Escaped wildcards get substituted incorrectly;
         
     | 
| 
      
 44 
     | 
    
         
            +
                      #       replace with FSM?
         
     | 
| 
      
 45 
     | 
    
         
            +
                      PATTERNS.each do |pattern|
         
     | 
| 
      
 46 
     | 
    
         
            +
                        exclude = exclude.gsub(pattern[0], pattern[1])
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
                      exclude
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end # << self
         
     | 
| 
      
 51 
     | 
    
         
            +
                end # ::Excludes
         
     | 
| 
      
 52 
     | 
    
         
            +
              end # ::Util
         
     | 
| 
      
 53 
     | 
    
         
            +
            end # ::VagrantReflect
         
     | 
| 
         @@ -0,0 +1,82 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'driskell-listen'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            # VagrantReflect module
         
     | 
| 
      
 5 
     | 
    
         
            +
            module VagrantReflect
         
     | 
| 
      
 6 
     | 
    
         
            +
              class ShutdownSignal < StandardError; end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              # Reflector instance
         
     | 
| 
      
 9 
     | 
    
         
            +
              class Reflector
         
     | 
| 
      
 10 
     | 
    
         
            +
                SIGNALS = %w(TERM INT).freeze
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(path)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @path = Pathname.new(File.expand_path(path))
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def run
         
     | 
| 
      
 17 
     | 
    
         
            +
                  setup_signals
         
     | 
| 
      
 18 
     | 
    
         
            +
                  start
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  @thread = Thread.current
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Thread.stop
         
     | 
| 
      
 22 
     | 
    
         
            +
                rescue ShutdownSignal
         
     | 
| 
      
 23 
     | 
    
         
            +
                  stop
         
     | 
| 
      
 24 
     | 
    
         
            +
                  shutdown_signals
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                protected
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def setup_signals
         
     | 
| 
      
 30 
     | 
    
         
            +
                  each_signal do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    raise ShutdownSignal
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def shutdown_signals
         
     | 
| 
      
 36 
     | 
    
         
            +
                  each_signal 'DEFAULT'
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def each_signal(command = nil, &block)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  SIGNALS.each do |signal|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    Signal.trap signal, block_given? ? block : command
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def start
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @listener = Driskell::Listen.to(@path, &method(:callback))
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @listener.start
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def stop
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @listener.stop if @listener.state != :stopped
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def record
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @record unless @record.nil?
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # TODO: This is a hack to get at the record data, we need to expose it in
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # the listen gem
         
     | 
| 
      
 59 
     | 
    
         
            +
                  backend = @listener.instance_variable_get(:@backend)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  adapter = backend.instance_variable_get(:@adapter)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  change = adapter.instance_variable_get(:@snapshots)[@path]
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @record = change.instance_variable_get(:@record)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def callback(modified, added, removed)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  output = {}
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  output[:added] = added.map(&method(:fetch_data))
         
     | 
| 
      
 69 
     | 
    
         
            +
                  output[:modified] = modified.map(&method(:fetch_data))
         
     | 
| 
      
 70 
     | 
    
         
            +
                  output[:removed] = removed
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  puts JSON.fast_generate(output)
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def fetch_data(path)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  rel_path = Pathname.new(path).relative_path_from(@path)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  data = record.file_data(rel_path)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  data[:path] = rel_path
         
     | 
| 
      
 79 
     | 
    
         
            +
                  data
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,136 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module VagrantReflect
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Util
         
     | 
| 
      
 3 
     | 
    
         
            +
                # This is a helper that builds the required commands and returns them
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Shell
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(machine, guestpath, hostpath, excludes)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @machine = machine
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @guestpath = guestpath
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @hostpath = hostpath
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @excludes = excludes || []
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    init_connection_info
         
     | 
| 
      
 12 
     | 
    
         
            +
                    init_commands
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  attr_reader :rsync_command_inc
         
     | 
| 
      
 16 
     | 
    
         
            +
                  attr_reader :rsync_command_full
         
     | 
| 
      
 17 
     | 
    
         
            +
                  attr_reader :rm_command
         
     | 
| 
      
 18 
     | 
    
         
            +
                  attr_reader :rmdir_command
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def init_connection_info
         
     | 
| 
      
 23 
     | 
    
         
            +
                    # Connection information
         
     | 
| 
      
 24 
     | 
    
         
            +
                    username = @machine.ssh_info[:username]
         
     | 
| 
      
 25 
     | 
    
         
            +
                    host     = @machine.ssh_info[:host]
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @remote = "#{username}@#{host}"
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @target = "#{@remote}:#{@guestpath}"
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def init_commands
         
     | 
| 
      
 31 
     | 
    
         
            +
                    @workdir = @machine.env.root_path.to_s
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    build_rsh_command
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    base = compile_base_rsync
         
     | 
| 
      
 36 
     | 
    
         
            +
                    build_rsync_command_full base
         
     | 
| 
      
 37 
     | 
    
         
            +
                    build_rsync_command_inc base
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    build_rm_command
         
     | 
| 
      
 40 
     | 
    
         
            +
                    build_rmdir_command
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def build_rsh_command
         
     | 
| 
      
 44 
     | 
    
         
            +
                    proxy_command = []
         
     | 
| 
      
 45 
     | 
    
         
            +
                    if @machine.ssh_info[:proxy_command]
         
     | 
| 
      
 46 
     | 
    
         
            +
                      proxy_command += [
         
     | 
| 
      
 47 
     | 
    
         
            +
                        '-o',
         
     | 
| 
      
 48 
     | 
    
         
            +
                        "ProxyCommand='#{@machine.ssh_info[:proxy_command]}'"
         
     | 
| 
      
 49 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    @rsh = rsh_command_args(proxy_command).flatten
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def rsh_command_args(proxy_command)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    [
         
     | 
| 
      
 57 
     | 
    
         
            +
                      'ssh',
         
     | 
| 
      
 58 
     | 
    
         
            +
                      '-p', @machine.ssh_info[:port].to_s,
         
     | 
| 
      
 59 
     | 
    
         
            +
                      proxy_command,
         
     | 
| 
      
 60 
     | 
    
         
            +
                      '-o', 'StrictHostKeyChecking=no',
         
     | 
| 
      
 61 
     | 
    
         
            +
                      '-o', 'IdentitiesOnly=true',
         
     | 
| 
      
 62 
     | 
    
         
            +
                      '-o', 'UserKnownHostsFile=/dev/null',
         
     | 
| 
      
 63 
     | 
    
         
            +
                      @machine.ssh_info[:private_key_path].map { |p| ['-i', p] }
         
     | 
| 
      
 64 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  def compile_base_rsync
         
     | 
| 
      
 68 
     | 
    
         
            +
                    # Get the command-line arguments
         
     | 
| 
      
 69 
     | 
    
         
            +
                    # TODO: Re-enable customisation of this
         
     | 
| 
      
 70 
     | 
    
         
            +
                    base_rsync = [
         
     | 
| 
      
 71 
     | 
    
         
            +
                      'rsync', '--verbose', '--archive', '--delete', '-z', '--links']
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    # On Windows, we have to set a default chmod flag to avoid permission
         
     | 
| 
      
 74 
     | 
    
         
            +
                    # issues
         
     | 
| 
      
 75 
     | 
    
         
            +
                    add_windows_chmod_args(base_rsync) if Vagrant::Util::Platform.windows?
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    add_owner_args(base_rsync)
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    base_rsync += ['-e', @rsh.join(' ')]
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    @excludes.map { |e| base_rsync += ['--exclude', e] }
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    base_rsync
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  def add_windows_chmod_args(base_rsync)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    return if base_rsync.any? { |arg| arg.start_with?('--chmod=') }
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                    # Ensures that all non-masked bits get enabled
         
     | 
| 
      
 90 
     | 
    
         
            +
                    base_rsync << '--chmod=ugo=rwX'
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    # Remove the -p option if --archive is enabled (--archive equals
         
     | 
| 
      
 93 
     | 
    
         
            +
                    # -rlptgoD) otherwise new files will not have the destination-default
         
     | 
| 
      
 94 
     | 
    
         
            +
                    # permissions
         
     | 
| 
      
 95 
     | 
    
         
            +
                    return unless base_rsync.include?('--archive') ||
         
     | 
| 
      
 96 
     | 
    
         
            +
                                  base_rsync.include?('-a')
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                    base_rsync << '--no-perms'
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  def add_owner_args(base_rsync)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    # Disable rsync's owner/group preservation (implied by --archive) unless
         
     | 
| 
      
 103 
     | 
    
         
            +
                    # specifically requested, since we adjust owner/group to match shared
         
     | 
| 
      
 104 
     | 
    
         
            +
                    # folder setting ourselves.
         
     | 
| 
      
 105 
     | 
    
         
            +
                    base_rsync << '--no-owner' unless
         
     | 
| 
      
 106 
     | 
    
         
            +
                      base_rsync.include?('--owner') || base_rsync.include?('-o')
         
     | 
| 
      
 107 
     | 
    
         
            +
                    base_rsync << '--no-group' unless
         
     | 
| 
      
 108 
     | 
    
         
            +
                      base_rsync.include?('--group') || base_rsync.include?('-g')
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  def build_rsync_command_full(base_rsync)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    @rsync_command_full = base_rsync + [
         
     | 
| 
      
 113 
     | 
    
         
            +
                      @hostpath, @target, { workdir: @workdir }]
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  def build_rsync_command_inc(base_rsync)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    @rsync_command_inc = base_rsync + [
         
     | 
| 
      
 118 
     | 
    
         
            +
                      '--files-from=-', @hostpath, @target,
         
     | 
| 
      
 119 
     | 
    
         
            +
                      { workdir: @workdir, notify: :stdin }]
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  def build_rm_command
         
     | 
| 
      
 123 
     | 
    
         
            +
                    @rm_command = @rsh + [
         
     | 
| 
      
 124 
     | 
    
         
            +
                      @remote, 'xargs rm -f', { workdir: @workdir, notify: :stdin }]
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                  def build_rmdir_command
         
     | 
| 
      
 128 
     | 
    
         
            +
                    # Make this command silent
         
     | 
| 
      
 129 
     | 
    
         
            +
                    # Sometimes we attempt to remove parent folders that aren't empty yet
         
     | 
| 
      
 130 
     | 
    
         
            +
                    # on the remote because we didn't yet sync across all of the removals
         
     | 
| 
      
 131 
     | 
    
         
            +
                    @rmdir_command = @rsh + [@remote, 'xargs -n 1 rmdir 2>/dev/null',
         
     | 
| 
      
 132 
     | 
    
         
            +
                                             { workdir: @workdir, notify: :stdin }]
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                end # ::Shell
         
     | 
| 
      
 135 
     | 
    
         
            +
              end # ::Util
         
     | 
| 
      
 136 
     | 
    
         
            +
            end # ::VagrantReflect
         
     | 
| 
         @@ -0,0 +1,146 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'vagrant/util/platform'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative '../patched/subprocess'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'shell'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module VagrantReflect
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Util
         
     | 
| 
      
 8 
     | 
    
         
            +
                # This is a helper that abstracts out the functionality of rsync and rm
         
     | 
| 
      
 9 
     | 
    
         
            +
                class Sync
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(machine, opts)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @machine = machine
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    init_paths(opts)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    @shell = Shell.new(@machine, @guestpath, @hostpath, opts[:excludes])
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    log_configuration opts[:excludes] || []
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def sync_incremental(items, &block)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    send_items_to_command items, @shell.rsync_command_inc, &block
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def sync_full
         
     | 
| 
      
 25 
     | 
    
         
            +
                    r = Vagrant::Util::SubprocessPatched.execute(*@shell.rsync_command_full)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    check_exit @shell.rsync_command_full, r
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def sync_removals(items, &block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    # Look for removed directories and fill in guest paths
         
     | 
| 
      
 31 
     | 
    
         
            +
                    dirs = prepare_items_for_removal(items)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    send_items_to_command items, @shell.rm_command, &block
         
     | 
| 
      
 34 
     | 
    
         
            +
                    sync_removals_parents dirs.values unless dirs.empty?
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def sync_removals_parents(guest_items)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    send_items_to_command guest_items, @shell.rmdir_command
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def log_configuration(excludes)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @machine.ui.info(
         
     | 
| 
      
 45 
     | 
    
         
            +
                      I18n.t(
         
     | 
| 
      
 46 
     | 
    
         
            +
                        'vagrant.plugins.vagrant-reflect.rsync_folder_configuration',
         
     | 
| 
      
 47 
     | 
    
         
            +
                        guestpath: @guestpath,
         
     | 
| 
      
 48 
     | 
    
         
            +
                        hostpath: @hostpath))
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    return if excludes.empty?
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    @machine.ui.info(
         
     | 
| 
      
 53 
     | 
    
         
            +
                      I18n.t(
         
     | 
| 
      
 54 
     | 
    
         
            +
                        'vagrant.plugins.vagrant-reflect.rsync_folder_excludes',
         
     | 
| 
      
 55 
     | 
    
         
            +
                        excludes: excludes.inspect))
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  def init_paths(opts)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # Folder info
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @guestpath = opts[:guestpath]
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @hostpath  = opts[:hostpath]
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @hostpath  = File.expand_path(@hostpath, @machine.env.root_path)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @hostpath  = Vagrant::Util::Platform.fs_real_path(@hostpath).to_s
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    if Vagrant::Util::Platform.windows?
         
     | 
| 
      
 66 
     | 
    
         
            +
                      # rsync for Windows expects cygwin style paths, always.
         
     | 
| 
      
 67 
     | 
    
         
            +
                      @hostpath = Vagrant::Util::Platform.cygwin_path(@hostpath)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    # Make sure the host path ends with a "/" to avoid creating
         
     | 
| 
      
 71 
     | 
    
         
            +
                    # a nested directory...
         
     | 
| 
      
 72 
     | 
    
         
            +
                    @hostpath += '/' unless @hostpath.end_with?('/')
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  def prepare_items_for_removal(items)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    dirs = {}
         
     | 
| 
      
 77 
     | 
    
         
            +
                    items.map! do |rel_path|
         
     | 
| 
      
 78 
     | 
    
         
            +
                      check_for_empty_parents(rel_path, dirs)
         
     | 
| 
      
 79 
     | 
    
         
            +
                      @guestpath + rel_path
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                    dirs
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  def check_for_empty_parents(rel_path, dirs)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    parent = rel_path
         
     | 
| 
      
 86 
     | 
    
         
            +
                    loop do
         
     | 
| 
      
 87 
     | 
    
         
            +
                      parent = File.dirname(parent)
         
     | 
| 
      
 88 
     | 
    
         
            +
                      break if parent == '/'
         
     | 
| 
      
 89 
     | 
    
         
            +
                      next if File.exist?(@hostpath + parent)
         
     | 
| 
      
 90 
     | 
    
         
            +
                      # Insertion order is maintained so ensure we move repeated paths to
         
     | 
| 
      
 91 
     | 
    
         
            +
                      # end so they are deleted last
         
     | 
| 
      
 92 
     | 
    
         
            +
                      dirs.delete parent
         
     | 
| 
      
 93 
     | 
    
         
            +
                      dirs[parent] = @guestpath + parent
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  def send_items_to_command(items, command, &block)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    current = next_item(items, &block)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    r = Vagrant::Util::SubprocessPatched.execute(*command) do |what, io|
         
     | 
| 
      
 100 
     | 
    
         
            +
                      next if what != :stdin
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                      current = process_items(io, items, current, &block)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
                    check_exit command, r
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  def process_items(io, items, current, &block)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    until current.nil?
         
     | 
| 
      
 109 
     | 
    
         
            +
                      send_data(io, current)
         
     | 
| 
      
 110 
     | 
    
         
            +
                      current = next_item(items, &block)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                    # Finished! Close stdin
         
     | 
| 
      
 114 
     | 
    
         
            +
                    io.close_write
         
     | 
| 
      
 115 
     | 
    
         
            +
                  rescue IO::WaitWritable, Errno::EINTR
         
     | 
| 
      
 116 
     | 
    
         
            +
                    # Wait for writable again
         
     | 
| 
      
 117 
     | 
    
         
            +
                    return current
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  def next_item(items)
         
     | 
| 
      
 121 
     | 
    
         
            +
                    return nil if items.empty?
         
     | 
| 
      
 122 
     | 
    
         
            +
                    current = items.shift + "\n"
         
     | 
| 
      
 123 
     | 
    
         
            +
                    yield current if block_given?
         
     | 
| 
      
 124 
     | 
    
         
            +
                    current
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                  def send_data(io, current)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    # Handle partial writes
         
     | 
| 
      
 129 
     | 
    
         
            +
                    n = io.write_nonblock(current)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    return unless n < current.length
         
     | 
| 
      
 131 
     | 
    
         
            +
                    current.slice! 0, n
         
     | 
| 
      
 132 
     | 
    
         
            +
                    throw IO::WaitWritable
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                  def check_exit(command, r)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    return if r.exit_code == 0
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                    raise Vagrant::Errors::RSyncError,
         
     | 
| 
      
 139 
     | 
    
         
            +
                          command: command.join(' '),
         
     | 
| 
      
 140 
     | 
    
         
            +
                          guestpath: @guestpath,
         
     | 
| 
      
 141 
     | 
    
         
            +
                          hostpath: @hostpath,
         
     | 
| 
      
 142 
     | 
    
         
            +
                          stderr: r.stderr
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
                end # ::Sync
         
     | 
| 
      
 145 
     | 
    
         
            +
              end # ::Util
         
     | 
| 
      
 146 
     | 
    
         
            +
            end # ::VagrantReflect
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: vagrant-reflect
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.7.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Jason Woods
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2016- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2016-05-17 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: driskell-listen
         
     | 
| 
         @@ -39,9 +39,13 @@ extra_rdoc_files: [] 
     | 
|
| 
       39 
39 
     | 
    
         
             
            files:
         
     | 
| 
       40 
40 
     | 
    
         
             
            - lib/vagrant-reflect.rb
         
     | 
| 
       41 
41 
     | 
    
         
             
            - lib/vagrant-reflect/command/reflect.rb
         
     | 
| 
      
 42 
     | 
    
         
            +
            - lib/vagrant-reflect/configuration/reflect.rb
         
     | 
| 
       42 
43 
     | 
    
         
             
            - lib/vagrant-reflect/patched/subprocess.rb
         
     | 
| 
       43 
44 
     | 
    
         
             
            - lib/vagrant-reflect/plugin.rb
         
     | 
| 
       44 
     | 
    
         
            -
            - lib/vagrant-reflect/util/ 
     | 
| 
      
 45 
     | 
    
         
            +
            - lib/vagrant-reflect/util/excludes.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/vagrant-reflect/util/reflector.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/vagrant-reflect/util/shell.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib/vagrant-reflect/util/sync.rb
         
     | 
| 
       45 
49 
     | 
    
         
             
            - lib/vagrant-reflect/version.rb
         
     | 
| 
       46 
50 
     | 
    
         
             
            - templates/locales/en.yml
         
     | 
| 
       47 
51 
     | 
    
         
             
            homepage: https://github.com/driskell/vagrant-reflect
         
     | 
| 
         @@ -1,327 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'vagrant/util/platform'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require_relative '../patched/subprocess'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module VagrantReflect
         
     | 
| 
       6 
     | 
    
         
            -
              # This is a helper that abstracts out the functionality of rsyncing
         
     | 
| 
       7 
     | 
    
         
            -
              # folders so that it can be called from anywhere.
         
     | 
| 
       8 
     | 
    
         
            -
              class Syncer
         
     | 
| 
       9 
     | 
    
         
            -
                RSYNC_TO_REGEXP_PATTERNS = [
         
     | 
| 
       10 
     | 
    
         
            -
                  ['.', '\\.'],
         
     | 
| 
       11 
     | 
    
         
            -
                  ['***', '|||EMPTY|||'],
         
     | 
| 
       12 
     | 
    
         
            -
                  ['**', '|||GLOBAL|||'],
         
     | 
| 
       13 
     | 
    
         
            -
                  ['*', '|||PATH|||'],
         
     | 
| 
       14 
     | 
    
         
            -
                  ['?', '[^/]'],
         
     | 
| 
       15 
     | 
    
         
            -
                  ['|||PATH|||', '[^/]+'],
         
     | 
| 
       16 
     | 
    
         
            -
                  ['|||GLOBAL|||', '.+'],
         
     | 
| 
       17 
     | 
    
         
            -
                  ['|||EMPTY|||', '.*']
         
     | 
| 
       18 
     | 
    
         
            -
                ].freeze
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                def initialize(machine, opts)
         
     | 
| 
       21 
     | 
    
         
            -
                  @opts = opts
         
     | 
| 
       22 
     | 
    
         
            -
                  @machine = machine
         
     | 
| 
       23 
     | 
    
         
            -
                  @workdir = @machine.env.root_path.to_s
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                  init_paths
         
     | 
| 
       26 
     | 
    
         
            -
                  init_connection_info
         
     | 
| 
       27 
     | 
    
         
            -
                  init_excludes
         
     | 
| 
       28 
     | 
    
         
            -
                  init_commands
         
     | 
| 
       29 
     | 
    
         
            -
                end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                def log_configuration
         
     | 
| 
       32 
     | 
    
         
            -
                  @machine.ui.info(
         
     | 
| 
       33 
     | 
    
         
            -
                    I18n.t(
         
     | 
| 
       34 
     | 
    
         
            -
                      'vagrant.plugins.vagrant-reflect.rsync_folder_configuration',
         
     | 
| 
       35 
     | 
    
         
            -
                      guestpath: @guestpath,
         
     | 
| 
       36 
     | 
    
         
            -
                      hostpath: @hostpath))
         
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
                  return if @excludes.empty?
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                  @machine.ui.info(
         
     | 
| 
       41 
     | 
    
         
            -
                    I18n.t(
         
     | 
| 
       42 
     | 
    
         
            -
                      'vagrant.plugins.vagrant-reflect.rsync_folder_excludes',
         
     | 
| 
       43 
     | 
    
         
            -
                      excludes: @excludes.inspect))
         
     | 
| 
       44 
     | 
    
         
            -
                end
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                # This converts the rsync exclude patterns to regular expressions we can
         
     | 
| 
       47 
     | 
    
         
            -
                # send to Listen.
         
     | 
| 
       48 
     | 
    
         
            -
                def excludes_to_regexp
         
     | 
| 
       49 
     | 
    
         
            -
                  return @regexp if @regexp
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                  @regexp = @excludes.map(&method(:exclude_to_regex_single))
         
     | 
| 
       52 
     | 
    
         
            -
                end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                def sync_incremental(items, &block)
         
     | 
| 
       55 
     | 
    
         
            -
                  send_items_to_command items, @rsync_command_inc, &block
         
     | 
| 
       56 
     | 
    
         
            -
                end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                def sync_full
         
     | 
| 
       59 
     | 
    
         
            -
                  r = Vagrant::Util::SubprocessPatched.execute(*@rsync_command_full)
         
     | 
| 
       60 
     | 
    
         
            -
                  check_exit @rsync_command_full, r
         
     | 
| 
       61 
     | 
    
         
            -
                end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
                def sync_removals(items, &block)
         
     | 
| 
       64 
     | 
    
         
            -
                  # Look for removed directories and fill in guest paths
         
     | 
| 
       65 
     | 
    
         
            -
                  dirs = prepare_items_for_removal(items)
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                  send_items_to_command items, @rm_command, &block
         
     | 
| 
       68 
     | 
    
         
            -
                  sync_removals_parents dirs.values, &block unless dirs.empty?
         
     | 
| 
       69 
     | 
    
         
            -
                end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                def sync_removals_parents(guest_items, &block)
         
     | 
| 
       72 
     | 
    
         
            -
                  send_items_to_command guest_items, @rmdir_command, &block
         
     | 
| 
       73 
     | 
    
         
            -
                end
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                protected
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                def init_paths
         
     | 
| 
       78 
     | 
    
         
            -
                  # Folder info
         
     | 
| 
       79 
     | 
    
         
            -
                  @guestpath = @opts[:guestpath]
         
     | 
| 
       80 
     | 
    
         
            -
                  @hostpath  = @opts[:hostpath]
         
     | 
| 
       81 
     | 
    
         
            -
                  @hostpath  = File.expand_path(@hostpath, @machine.env.root_path)
         
     | 
| 
       82 
     | 
    
         
            -
                  @hostpath  = Vagrant::Util::Platform.fs_real_path(@hostpath).to_s
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
                  if Vagrant::Util::Platform.windows?
         
     | 
| 
       85 
     | 
    
         
            -
                    # rsync for Windows expects cygwin style paths, always.
         
     | 
| 
       86 
     | 
    
         
            -
                    @hostpath = Vagrant::Util::Platform.cygwin_path(@hostpath)
         
     | 
| 
       87 
     | 
    
         
            -
                  end
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                  # Make sure the host path ends with a "/" to avoid creating
         
     | 
| 
       90 
     | 
    
         
            -
                  # a nested directory...
         
     | 
| 
       91 
     | 
    
         
            -
                  @hostpath += '/' unless @hostpath.end_with?('/')
         
     | 
| 
       92 
     | 
    
         
            -
                end
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                def init_connection_info
         
     | 
| 
       95 
     | 
    
         
            -
                  # Connection information
         
     | 
| 
       96 
     | 
    
         
            -
                  username = @machine.ssh_info[:username]
         
     | 
| 
       97 
     | 
    
         
            -
                  host     = @machine.ssh_info[:host]
         
     | 
| 
       98 
     | 
    
         
            -
                  @remote = "#{username}@#{host}"
         
     | 
| 
       99 
     | 
    
         
            -
                  @target = "#{@remote}:#{@guestpath}"
         
     | 
| 
       100 
     | 
    
         
            -
                end
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                def init_excludes
         
     | 
| 
       103 
     | 
    
         
            -
                  # Exclude some files by default, and any that might be configured
         
     | 
| 
       104 
     | 
    
         
            -
                  # by the user.
         
     | 
| 
       105 
     | 
    
         
            -
                  @excludes = []
         
     | 
| 
       106 
     | 
    
         
            -
                  @excludes += Array(@opts[:exclude]).map(&:to_s) if @opts[:exclude]
         
     | 
| 
       107 
     | 
    
         
            -
                  @excludes.uniq!
         
     | 
| 
       108 
     | 
    
         
            -
                end
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
                def init_commands
         
     | 
| 
       111 
     | 
    
         
            -
                  init_rsh_command
         
     | 
| 
       112 
     | 
    
         
            -
                  init_rsync_command
         
     | 
| 
       113 
     | 
    
         
            -
                  init_rsync_command_full
         
     | 
| 
       114 
     | 
    
         
            -
                  init_rsync_command_inc
         
     | 
| 
       115 
     | 
    
         
            -
                  init_rm_command
         
     | 
| 
       116 
     | 
    
         
            -
                  init_rmdir_command
         
     | 
| 
       117 
     | 
    
         
            -
                end
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
                def init_rsh_command
         
     | 
| 
       120 
     | 
    
         
            -
                  proxy_command = []
         
     | 
| 
       121 
     | 
    
         
            -
                  if @machine.ssh_info[:proxy_command]
         
     | 
| 
       122 
     | 
    
         
            -
                    proxy_command += [
         
     | 
| 
       123 
     | 
    
         
            -
                      '-o',
         
     | 
| 
       124 
     | 
    
         
            -
                      "ProxyCommand='#{@machine.ssh_info[:proxy_command]}'"
         
     | 
| 
       125 
     | 
    
         
            -
                    ]
         
     | 
| 
       126 
     | 
    
         
            -
                  end
         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
                  @rsh = build_rsh_command(proxy_command).flatten
         
     | 
| 
       129 
     | 
    
         
            -
                end
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                def build_rsh_command(proxy_command)
         
     | 
| 
       132 
     | 
    
         
            -
                  [
         
     | 
| 
       133 
     | 
    
         
            -
                    'ssh',
         
     | 
| 
       134 
     | 
    
         
            -
                    '-p', @machine.ssh_info[:port].to_s,
         
     | 
| 
       135 
     | 
    
         
            -
                    proxy_command,
         
     | 
| 
       136 
     | 
    
         
            -
                    '-o', 'StrictHostKeyChecking=no',
         
     | 
| 
       137 
     | 
    
         
            -
                    '-o', 'IdentitiesOnly=true',
         
     | 
| 
       138 
     | 
    
         
            -
                    '-o', 'UserKnownHostsFile=/dev/null',
         
     | 
| 
       139 
     | 
    
         
            -
                    @machine.ssh_info[:private_key_path].map { |p| ['-i', p] }
         
     | 
| 
       140 
     | 
    
         
            -
                  ]
         
     | 
| 
       141 
     | 
    
         
            -
                end
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                def init_rsync_command
         
     | 
| 
       144 
     | 
    
         
            -
                  # Get the command-line arguments
         
     | 
| 
       145 
     | 
    
         
            -
                  if @opts[:args]
         
     | 
| 
       146 
     | 
    
         
            -
                    @rsync_command = ['rsync'] + Array(@opts[:args]).dup
         
     | 
| 
       147 
     | 
    
         
            -
                  else
         
     | 
| 
       148 
     | 
    
         
            -
                    @rsync_command = [
         
     | 
| 
       149 
     | 
    
         
            -
                      'rsync', '--verbose', '--archive', '--delete', '-z', '--copy-links']
         
     | 
| 
       150 
     | 
    
         
            -
                  end
         
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
                  # On Windows, we have to set a default chmod flag to avoid permission
         
     | 
| 
       153 
     | 
    
         
            -
                  # issues
         
     | 
| 
       154 
     | 
    
         
            -
                  build_windows_chmod_args if Vagrant::Util::Platform.windows?
         
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
       156 
     | 
    
         
            -
                  build_owner_args
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
                  @rsync_command += ['-e', @rsh.join(' ')]
         
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
                  @excludes.map { |e| @rsync_command += ['--exclude', e] }
         
     | 
| 
       161 
     | 
    
         
            -
                end
         
     | 
| 
       162 
     | 
    
         
            -
             
     | 
| 
       163 
     | 
    
         
            -
                def build_windows_chmod_args
         
     | 
| 
       164 
     | 
    
         
            -
                  return if @rsync_command.any? { |arg| arg.start_with?('--chmod=') }
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
                  # Ensures that all non-masked bits get enabled
         
     | 
| 
       167 
     | 
    
         
            -
                  @rsync_command << '--chmod=ugo=rwX'
         
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                  # Remove the -p option if --archive is enabled (--archive equals
         
     | 
| 
       170 
     | 
    
         
            -
                  # -rlptgoD) otherwise new files will not have the destination-default
         
     | 
| 
       171 
     | 
    
         
            -
                  # permissions
         
     | 
| 
       172 
     | 
    
         
            -
                  return unless @rsync_command.include?('--archive') ||
         
     | 
| 
       173 
     | 
    
         
            -
                                @rsync_command.include?('-a')
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                  @rsync_command << '--no-perms'
         
     | 
| 
       176 
     | 
    
         
            -
                end
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                def build_owner_args
         
     | 
| 
       179 
     | 
    
         
            -
                  # Disable rsync's owner/group preservation (implied by --archive) unless
         
     | 
| 
       180 
     | 
    
         
            -
                  # specifically requested, since we adjust owner/group to match shared
         
     | 
| 
       181 
     | 
    
         
            -
                  # folder setting ourselves.
         
     | 
| 
       182 
     | 
    
         
            -
                  @rsync_command << '--no-owner' unless
         
     | 
| 
       183 
     | 
    
         
            -
                    @rsync_command.include?('--owner') || @rsync_command.include?('-o')
         
     | 
| 
       184 
     | 
    
         
            -
                  @rsync_command << '--no-group' unless
         
     | 
| 
       185 
     | 
    
         
            -
                    @rsync_command.include?('--group') || @rsync_command.include?('-g')
         
     | 
| 
       186 
     | 
    
         
            -
                end
         
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
       188 
     | 
    
         
            -
                def init_rsync_command_full
         
     | 
| 
       189 
     | 
    
         
            -
                  @rsync_command_full = @rsync_command.dup + [
         
     | 
| 
       190 
     | 
    
         
            -
                    @hostpath,
         
     | 
| 
       191 
     | 
    
         
            -
                    @target,
         
     | 
| 
       192 
     | 
    
         
            -
                    {
         
     | 
| 
       193 
     | 
    
         
            -
                      workdir: @workdir
         
     | 
| 
       194 
     | 
    
         
            -
                    }
         
     | 
| 
       195 
     | 
    
         
            -
                  ]
         
     | 
| 
       196 
     | 
    
         
            -
                end
         
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                def init_rsync_command_inc
         
     | 
| 
       199 
     | 
    
         
            -
                  @rsync_command_inc = @rsync_command.dup + [
         
     | 
| 
       200 
     | 
    
         
            -
                    '--files-from=-',
         
     | 
| 
       201 
     | 
    
         
            -
                    @hostpath,
         
     | 
| 
       202 
     | 
    
         
            -
                    @target,
         
     | 
| 
       203 
     | 
    
         
            -
                    {
         
     | 
| 
       204 
     | 
    
         
            -
                      workdir: @workdir,
         
     | 
| 
       205 
     | 
    
         
            -
                      notify: :stdin
         
     | 
| 
       206 
     | 
    
         
            -
                    }
         
     | 
| 
       207 
     | 
    
         
            -
                  ]
         
     | 
| 
       208 
     | 
    
         
            -
                end
         
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
                def init_rm_command
         
     | 
| 
       211 
     | 
    
         
            -
                  @rm_command = @rsh.dup + [
         
     | 
| 
       212 
     | 
    
         
            -
                    @remote,
         
     | 
| 
       213 
     | 
    
         
            -
                    'xargs rm -f',
         
     | 
| 
       214 
     | 
    
         
            -
                    {
         
     | 
| 
       215 
     | 
    
         
            -
                      workdir: @workdir,
         
     | 
| 
       216 
     | 
    
         
            -
                      notify: :stdin
         
     | 
| 
       217 
     | 
    
         
            -
                    }
         
     | 
| 
       218 
     | 
    
         
            -
                  ]
         
     | 
| 
       219 
     | 
    
         
            -
                end
         
     | 
| 
       220 
     | 
    
         
            -
             
     | 
| 
       221 
     | 
    
         
            -
                def init_rmdir_command
         
     | 
| 
       222 
     | 
    
         
            -
                  @rmdir_command = @rsh.dup + [
         
     | 
| 
       223 
     | 
    
         
            -
                    @remote,
         
     | 
| 
       224 
     | 
    
         
            -
                    'xargs rmdir',
         
     | 
| 
       225 
     | 
    
         
            -
                    {
         
     | 
| 
       226 
     | 
    
         
            -
                      workdir: @workdir,
         
     | 
| 
       227 
     | 
    
         
            -
                      notify: :stdin
         
     | 
| 
       228 
     | 
    
         
            -
                    }
         
     | 
| 
       229 
     | 
    
         
            -
                  ]
         
     | 
| 
       230 
     | 
    
         
            -
                end
         
     | 
| 
       231 
     | 
    
         
            -
             
     | 
| 
       232 
     | 
    
         
            -
                def prepare_items_for_removal(items)
         
     | 
| 
       233 
     | 
    
         
            -
                  dirs = {}
         
     | 
| 
       234 
     | 
    
         
            -
                  items.map! do |rel_path|
         
     | 
| 
       235 
     | 
    
         
            -
                    check_for_empty_parents(rel_path, dirs)
         
     | 
| 
       236 
     | 
    
         
            -
                    @guestpath + rel_path
         
     | 
| 
       237 
     | 
    
         
            -
                  end
         
     | 
| 
       238 
     | 
    
         
            -
                  dirs
         
     | 
| 
       239 
     | 
    
         
            -
                end
         
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
       241 
     | 
    
         
            -
                def check_for_empty_parents(rel_path, dirs)
         
     | 
| 
       242 
     | 
    
         
            -
                  parent = rel_path
         
     | 
| 
       243 
     | 
    
         
            -
                  loop do
         
     | 
| 
       244 
     | 
    
         
            -
                    parent = File.dirname(parent)
         
     | 
| 
       245 
     | 
    
         
            -
                    break if parent == '/'
         
     | 
| 
       246 
     | 
    
         
            -
                    next if File.exist?(@hostpath + parent)
         
     | 
| 
       247 
     | 
    
         
            -
                    # Insertion order is maintained so ensure we move repeated paths to
         
     | 
| 
       248 
     | 
    
         
            -
                    # end so they are deleted last
         
     | 
| 
       249 
     | 
    
         
            -
                    dirs.delete parent
         
     | 
| 
       250 
     | 
    
         
            -
                    dirs[parent] = @guestpath + parent
         
     | 
| 
       251 
     | 
    
         
            -
                  end
         
     | 
| 
       252 
     | 
    
         
            -
                end
         
     | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
       254 
     | 
    
         
            -
                def send_items_to_command(items, command, &block)
         
     | 
| 
       255 
     | 
    
         
            -
                  current = next_item(items, &block)
         
     | 
| 
       256 
     | 
    
         
            -
                  r = Vagrant::Util::SubprocessPatched.execute(*command) do |what, io|
         
     | 
| 
       257 
     | 
    
         
            -
                    next if what != :stdin
         
     | 
| 
       258 
     | 
    
         
            -
             
     | 
| 
       259 
     | 
    
         
            -
                    current = process_items(io, items, current, &block)
         
     | 
| 
       260 
     | 
    
         
            -
                  end
         
     | 
| 
       261 
     | 
    
         
            -
                  check_exit command, r
         
     | 
| 
       262 
     | 
    
         
            -
                end
         
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
     | 
    
         
            -
                def process_items(io, items, current, &block)
         
     | 
| 
       265 
     | 
    
         
            -
                  until current.nil?
         
     | 
| 
       266 
     | 
    
         
            -
                    send_data(io, current)
         
     | 
| 
       267 
     | 
    
         
            -
                    current = next_item(items, &block)
         
     | 
| 
       268 
     | 
    
         
            -
                  end
         
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
       270 
     | 
    
         
            -
                  # Finished! Close stdin
         
     | 
| 
       271 
     | 
    
         
            -
                  io.close_write
         
     | 
| 
       272 
     | 
    
         
            -
                rescue IO::WaitWritable, Errno::EINTR
         
     | 
| 
       273 
     | 
    
         
            -
                  # Wait for writable again
         
     | 
| 
       274 
     | 
    
         
            -
                  return current
         
     | 
| 
       275 
     | 
    
         
            -
                end
         
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
       277 
     | 
    
         
            -
                def next_item(items)
         
     | 
| 
       278 
     | 
    
         
            -
                  return nil if items.empty?
         
     | 
| 
       279 
     | 
    
         
            -
                  current = items.shift + "\n"
         
     | 
| 
       280 
     | 
    
         
            -
                  yield current if block_given?
         
     | 
| 
       281 
     | 
    
         
            -
                  current
         
     | 
| 
       282 
     | 
    
         
            -
                end
         
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
                def send_data(io, current)
         
     | 
| 
       285 
     | 
    
         
            -
                  # Handle partial writes
         
     | 
| 
       286 
     | 
    
         
            -
                  n = io.write_nonblock(current)
         
     | 
| 
       287 
     | 
    
         
            -
                  return unless n < current.length
         
     | 
| 
       288 
     | 
    
         
            -
                  current.slice! 0, n
         
     | 
| 
       289 
     | 
    
         
            -
                  throw IO::WaitWritable
         
     | 
| 
       290 
     | 
    
         
            -
                end
         
     | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
       292 
     | 
    
         
            -
                def check_exit(command, r)
         
     | 
| 
       293 
     | 
    
         
            -
                  return if r.exit_code == 0
         
     | 
| 
       294 
     | 
    
         
            -
             
     | 
| 
       295 
     | 
    
         
            -
                  raise Vagrant::Errors::RSyncError,
         
     | 
| 
       296 
     | 
    
         
            -
                        command: command.join(' '),
         
     | 
| 
       297 
     | 
    
         
            -
                        guestpath: @guestpath,
         
     | 
| 
       298 
     | 
    
         
            -
                        hostpath: @hostpath,
         
     | 
| 
       299 
     | 
    
         
            -
                        stderr: r.stderr
         
     | 
| 
       300 
     | 
    
         
            -
                end
         
     | 
| 
       301 
     | 
    
         
            -
             
     | 
| 
       302 
     | 
    
         
            -
                def exclude_to_regex_single(exclude)
         
     | 
| 
       303 
     | 
    
         
            -
                  start_anchor = false
         
     | 
| 
       304 
     | 
    
         
            -
             
     | 
| 
       305 
     | 
    
         
            -
                  if exclude.start_with?('/')
         
     | 
| 
       306 
     | 
    
         
            -
                    start_anchor = true
         
     | 
| 
       307 
     | 
    
         
            -
                    exclude = exclude[1..-1]
         
     | 
| 
       308 
     | 
    
         
            -
                  end
         
     | 
| 
       309 
     | 
    
         
            -
             
     | 
| 
       310 
     | 
    
         
            -
                  regexp = start_anchor ? '^' : '(?:^|/)'
         
     | 
| 
       311 
     | 
    
         
            -
                  regexp += perform_substitutions(exclude)
         
     | 
| 
       312 
     | 
    
         
            -
                  regexp += exclude.end_with?('/') ? '' : '(?:/|$)'
         
     | 
| 
       313 
     | 
    
         
            -
             
     | 
| 
       314 
     | 
    
         
            -
                  Regexp.new(regexp)
         
     | 
| 
       315 
     | 
    
         
            -
                end
         
     | 
| 
       316 
     | 
    
         
            -
             
     | 
| 
       317 
     | 
    
         
            -
                def perform_substitutions(exclude)
         
     | 
| 
       318 
     | 
    
         
            -
                  # This is REALLY ghetto, but its a start. We can improve and
         
     | 
| 
       319 
     | 
    
         
            -
                  # keep unit tests passing in the future.
         
     | 
| 
       320 
     | 
    
         
            -
                  # TODO: Escaped wildcards get substituted incorrectly - replace with FSM?
         
     | 
| 
       321 
     | 
    
         
            -
                  RSYNC_TO_REGEXP_PATTERNS.each do |pattern|
         
     | 
| 
       322 
     | 
    
         
            -
                    exclude = exclude.gsub(pattern[0], pattern[1])
         
     | 
| 
       323 
     | 
    
         
            -
                  end
         
     | 
| 
       324 
     | 
    
         
            -
                  exclude
         
     | 
| 
       325 
     | 
    
         
            -
                end
         
     | 
| 
       326 
     | 
    
         
            -
              end
         
     | 
| 
       327 
     | 
    
         
            -
            end
         
     |