vagrant-reflect 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/vagrant-reflect/command/reflect.rb +43 -92
- data/lib/vagrant-reflect/util/syncer.rb +214 -0
- data/lib/vagrant-reflect/version.rb +1 -1
- data/templates/locales/en.yml +6 -6
- metadata +3 -3
- data/lib/vagrant-reflect/helper.rb +0 -169
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10bf068f0fcd1751185c72edc2b8a9d0f9d3fc62
|
4
|
+
data.tar.gz: 62751eb5164e9a8f7bfd1f9d8793d245a300de67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5639afa42e9dc1767a9a29978dbcbed82904fa70b079d12d3c72ee4bec3c93751ea1422ad8838911383426a14d7e56bfb0a1b241af353340f9603fd29366c91
|
7
|
+
data.tar.gz: 2fe41628e246d06af901be938cded207f5a635a627cf1844f2d3ffdbeeda2f47f8319f9898c9d0170734eed42e700217254e98b049d3ee78bcfbe3965e1e7ae5
|
@@ -6,7 +6,7 @@ require 'vagrant/action/builtin/mixin_synced_folders'
|
|
6
6
|
require 'vagrant/util/busy'
|
7
7
|
require 'vagrant/util/platform'
|
8
8
|
|
9
|
-
require_relative '../
|
9
|
+
require_relative '../util/syncer'
|
10
10
|
|
11
11
|
require 'driskell-listen'
|
12
12
|
|
@@ -74,29 +74,30 @@ module VagrantReflect
|
|
74
74
|
folders = cached[:rsync]
|
75
75
|
next if !folders || folders.empty?
|
76
76
|
|
77
|
-
# Get the SSH info for this machine so we can do an initial
|
78
|
-
# sync to the VM.
|
79
|
-
ssh_info = machine.ssh_info
|
80
|
-
if ssh_info
|
81
|
-
machine.ui.info(
|
82
|
-
I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_initial'))
|
83
|
-
folders.each do |_, folder_opts|
|
84
|
-
SyncHelper.sync_single(machine, ssh_info, folder_opts)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
77
|
folders.each do |id, folder_opts|
|
89
78
|
# If we marked this folder to not auto sync, then
|
90
79
|
# don't do it.
|
91
80
|
next if folder_opts.key?(:auto) && !folder_opts[:auto]
|
92
81
|
|
82
|
+
# Push on .vagrant exclude
|
83
|
+
folder_opts = folder_opts.dup
|
84
|
+
folder_opts[:exclude] ||= []
|
85
|
+
folder_opts[:exclude] << '.vagrant/'
|
86
|
+
|
87
|
+
syncer = Syncer.new(machine, folder_opts)
|
88
|
+
|
89
|
+
machine.ui.info(
|
90
|
+
I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_initial'))
|
91
|
+
syncer.sync_full
|
92
|
+
|
93
93
|
hostpath = folder_opts[:hostpath]
|
94
94
|
hostpath = File.expand_path(hostpath, machine.env.root_path)
|
95
95
|
paths[hostpath] ||= []
|
96
96
|
paths[hostpath] << {
|
97
|
-
id:
|
97
|
+
id: id,
|
98
98
|
machine: machine,
|
99
|
-
opts: folder_opts
|
99
|
+
opts: folder_opts,
|
100
|
+
syncer: syncer
|
100
101
|
}
|
101
102
|
end
|
102
103
|
end
|
@@ -124,10 +125,10 @@ module VagrantReflect
|
|
124
125
|
'vagrant.plugins.vagrant-reflect.rsync_auto_path',
|
125
126
|
path: path.to_s))
|
126
127
|
|
127
|
-
next unless path_opts[:exclude]
|
128
|
+
next unless path_opts[:opts][:exclude]
|
128
129
|
|
129
|
-
Array(path_opts[:exclude]).each do |pattern|
|
130
|
-
ignores <<
|
130
|
+
Array(path_opts[:opts][:exclude]).each do |pattern|
|
131
|
+
ignores << Syncer.exclude_to_regexp(pattern.to_s)
|
131
132
|
end
|
132
133
|
end
|
133
134
|
|
@@ -171,13 +172,6 @@ module VagrantReflect
|
|
171
172
|
|
172
173
|
# Perform the sync for each machine
|
173
174
|
opts.each do |path_opts|
|
174
|
-
# Reload so we get the latest ID
|
175
|
-
path_opts[:machine].reload
|
176
|
-
if !path_opts[:machine].id || path_opts[:machine].id == ''
|
177
|
-
# Skip since we can't get SSH info without an ID
|
178
|
-
next
|
179
|
-
end
|
180
|
-
|
181
175
|
begin
|
182
176
|
# If we have any removals or have disabled incremental, perform a
|
183
177
|
# single full sync
|
@@ -185,25 +179,33 @@ module VagrantReflect
|
|
185
179
|
if !options[:incremental] || !removed.empty?
|
186
180
|
removed.each do |remove|
|
187
181
|
path_opts[:machine].ui.info(
|
188
|
-
I18n.t(
|
189
|
-
|
182
|
+
I18n.t(
|
183
|
+
'vagrant.plugins.vagrant-reflect.rsync_auto_full_remove',
|
184
|
+
path: strip_path(path, remove)))
|
190
185
|
end
|
191
186
|
|
192
187
|
[modified, added].each do |changes|
|
193
188
|
changes.each do |change|
|
194
189
|
path_opts[:machine].ui.info(
|
195
|
-
I18n.t(
|
196
|
-
|
190
|
+
I18n.t(
|
191
|
+
'vagrant.plugins.vagrant-reflect.rsync_auto_full_change',
|
192
|
+
path: strip_path(path, change)))
|
197
193
|
end
|
198
194
|
end
|
199
195
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
)
|
196
|
+
path_opts[:machine].ui.info(
|
197
|
+
I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_full'))
|
198
|
+
|
199
|
+
path_opts[:syncer].sync_full
|
205
200
|
elsif !modified.empty? || !added.empty?
|
206
|
-
|
201
|
+
# Pass the list of changes to rsync so we quickly synchronise only
|
202
|
+
# the changed files instead of the whole folder
|
203
|
+
items = strip_paths(path, modified + added)
|
204
|
+
path_opts[:syncer].sync_incremental(items) do |item|
|
205
|
+
path_opts[:machine].ui.info(
|
206
|
+
I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_increment',
|
207
|
+
path: item))
|
208
|
+
end
|
207
209
|
end
|
208
210
|
|
209
211
|
path_opts[:machine].ui.info(
|
@@ -215,70 +217,19 @@ module VagrantReflect
|
|
215
217
|
I18n.t('vagrant.plugins.vagrant-reflect.'\
|
216
218
|
'rsync_communicator_not_ready_callback'))
|
217
219
|
rescue Vagrant::Errors::VagrantError => e
|
218
|
-
path_opts[:machine].ui.error(e)
|
220
|
+
path_opts[:machine].ui.error(e.message)
|
219
221
|
end
|
220
222
|
end
|
221
223
|
end
|
222
224
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
line = sets[0].pop
|
228
|
-
sets.shift while !sets.empty? && sets[0].empty?
|
229
|
-
line[path.length..line.length] + "\n"
|
225
|
+
def strip_paths(path, items)
|
226
|
+
items.map do |item|
|
227
|
+
item[path.length..-1]
|
228
|
+
end
|
230
229
|
end
|
231
230
|
|
232
|
-
def
|
233
|
-
|
234
|
-
sets.shift while sets[0].empty?
|
235
|
-
line = false
|
236
|
-
|
237
|
-
# Pass the list of changes to rsync so we quickly synchronise only
|
238
|
-
# the changed files instead of the whole folder
|
239
|
-
SyncHelper.sync_single(
|
240
|
-
path_opts[:machine],
|
241
|
-
path_opts[:machine].ssh_info,
|
242
|
-
path_opts[:opts].merge(from_stdin: true)
|
243
|
-
) do |what, io|
|
244
|
-
next if what != :stdin
|
245
|
-
|
246
|
-
if line.nil?
|
247
|
-
io.close_write
|
248
|
-
next
|
249
|
-
end
|
250
|
-
|
251
|
-
begin
|
252
|
-
loop do
|
253
|
-
# If we don't have a line, grab one and print it
|
254
|
-
unless line
|
255
|
-
line = next_change(sets, path)
|
256
|
-
path_opts[:machine].ui.info(
|
257
|
-
I18n.t('vagrant.plugins.vagrant-reflect.rsync_auto_increment',
|
258
|
-
path: line))
|
259
|
-
end
|
260
|
-
|
261
|
-
# Handle partial writes
|
262
|
-
n = io.write_nonblock(line)
|
263
|
-
if n < line.length
|
264
|
-
line = line[n..line.length]
|
265
|
-
break
|
266
|
-
end
|
267
|
-
|
268
|
-
# When we've finished giving rsync the file list, set line to nil
|
269
|
-
# and return - on the next notify we will EOT stdin
|
270
|
-
if sets.empty?
|
271
|
-
line = nil
|
272
|
-
break
|
273
|
-
end
|
274
|
-
|
275
|
-
# Request a new line for next write
|
276
|
-
line = false
|
277
|
-
end
|
278
|
-
rescue IO::WaitWritable, Errno::EINTR
|
279
|
-
# Ignore
|
280
|
-
end
|
281
|
-
end
|
231
|
+
def strip_path(path, item)
|
232
|
+
item[path.length..-1]
|
282
233
|
end
|
283
234
|
end
|
284
235
|
end
|
@@ -0,0 +1,214 @@
|
|
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
|
+
# This converts an rsync exclude pattern to a regular expression
|
10
|
+
# we can send to Listen.
|
11
|
+
def self.exclude_to_regexp(exclude)
|
12
|
+
start_anchor = false
|
13
|
+
dir_only = false
|
14
|
+
|
15
|
+
if exclude.start_with?('/')
|
16
|
+
start_anchor = true
|
17
|
+
exclude = exclude[1..-1]
|
18
|
+
end
|
19
|
+
|
20
|
+
if exclude.end_with?('/')
|
21
|
+
dir_only = true
|
22
|
+
exclude = exclude[0..-2]
|
23
|
+
end
|
24
|
+
|
25
|
+
regexp = start_anchor ? '^' : '(?:^|/)'
|
26
|
+
|
27
|
+
# This is REALLY ghetto, but its a start. We can improve and
|
28
|
+
# keep unit tests passing in the future.
|
29
|
+
# TODO: Escaped wildcards get substituted incorrectly - replace with FSM?
|
30
|
+
exclude = exclude.gsub('.', '\\.')
|
31
|
+
exclude = exclude.gsub('***', '|||EMPTY|||')
|
32
|
+
exclude = exclude.gsub('**', '|||GLOBAL|||')
|
33
|
+
exclude = exclude.gsub('*', '|||PATH|||')
|
34
|
+
exclude = exclude.gsub('?', '[^/]')
|
35
|
+
exclude = exclude.gsub('|||PATH|||', '[^/]+')
|
36
|
+
exclude = exclude.gsub('|||GLOBAL|||', '.+')
|
37
|
+
exclude = exclude.gsub('|||EMPTY|||', '.*')
|
38
|
+
regexp += exclude
|
39
|
+
|
40
|
+
regexp += dir_only ? '/' : '(?:/|$)'
|
41
|
+
|
42
|
+
Regexp.new(regexp)
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(machine, opts)
|
46
|
+
@opts = opts
|
47
|
+
@machine = machine
|
48
|
+
@workdir = @machine.env.root_path.to_s
|
49
|
+
|
50
|
+
# Folder info
|
51
|
+
@guestpath = @opts[:guestpath]
|
52
|
+
@hostpath = @opts[:hostpath]
|
53
|
+
@hostpath = File.expand_path(@hostpath, machine.env.root_path)
|
54
|
+
@hostpath = Vagrant::Util::Platform.fs_real_path(@hostpath).to_s
|
55
|
+
|
56
|
+
if Vagrant::Util::Platform.windows?
|
57
|
+
# rsync for Windows expects cygwin style paths, always.
|
58
|
+
@hostpath = Vagrant::Util::Platform.cygwin_path(@hostpath)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Make sure the host path ends with a "/" to avoid creating
|
62
|
+
# a nested directory...
|
63
|
+
@hostpath += '/' unless @hostpath.end_with?('/')
|
64
|
+
|
65
|
+
# Connection information
|
66
|
+
username = @machine.ssh_info[:username]
|
67
|
+
host = @machine.ssh_info[:host]
|
68
|
+
proxy_command = ''
|
69
|
+
if @machine.ssh_info[:proxy_command]
|
70
|
+
proxy_command = "-o ProxyCommand='#{@machine.ssh_info[:proxy_command]}' "
|
71
|
+
end
|
72
|
+
|
73
|
+
rsh = [
|
74
|
+
"ssh -p #{@machine.ssh_info[:port]} " +
|
75
|
+
proxy_command +
|
76
|
+
'-o StrictHostKeyChecking=no '\
|
77
|
+
'-o IdentitiesOnly=true '\
|
78
|
+
'-o UserKnownHostsFile=/dev/null',
|
79
|
+
@machine.ssh_info[:private_key_path].map { |p| "-i '#{p}'" }
|
80
|
+
].flatten.join(' ')
|
81
|
+
|
82
|
+
@target = "#{username}@#{host}:#{@guestpath}"
|
83
|
+
|
84
|
+
# Exclude some files by default, and any that might be configured
|
85
|
+
# by the user.
|
86
|
+
excludes = []
|
87
|
+
excludes += Array(@opts[:exclude]).map(&:to_s) if @opts[:exclude]
|
88
|
+
excludes.uniq!
|
89
|
+
|
90
|
+
# Get the command-line arguments
|
91
|
+
@command = ['rsync']
|
92
|
+
@command += Array(@opts[:args]).dup if @opts[:args]
|
93
|
+
@command ||= ['--verbose', '--archive', '--delete', '-z', '--copy-links']
|
94
|
+
|
95
|
+
# On Windows, we have to set a default chmod flag to avoid permission
|
96
|
+
# issues
|
97
|
+
if Vagrant::Util::Platform.windows?
|
98
|
+
unless @command.any? { |arg| arg.start_with?('--chmod=') }
|
99
|
+
# Ensures that all non-masked bits get enabled
|
100
|
+
@command << '--chmod=ugo=rwX'
|
101
|
+
|
102
|
+
# Remove the -p option if --archive is enabled (--archive equals
|
103
|
+
# -rlptgoD) otherwise new files will not have the destination-default
|
104
|
+
# permissions
|
105
|
+
@command << '--no-perms' if
|
106
|
+
@command.include?('--archive') || @command.include?('-a')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Disable rsync's owner/group preservation (implied by --archive) unless
|
111
|
+
# specifically requested, since we adjust owner/group to match shared
|
112
|
+
# folder setting ourselves.
|
113
|
+
@command << '--no-owner' unless
|
114
|
+
@command.include?('--owner') || @command.include?('-o')
|
115
|
+
@command << '--no-group' unless
|
116
|
+
@command.include?('--group') || @command.include?('-g')
|
117
|
+
|
118
|
+
# Tell local rsync how to invoke remote rsync with sudo
|
119
|
+
if @machine.guest.capability?(:rsync_command)
|
120
|
+
@command << '--rsync-path' << @machine.guest.capability(:rsync_command)
|
121
|
+
end
|
122
|
+
|
123
|
+
@command += [
|
124
|
+
'-e', rsh
|
125
|
+
]
|
126
|
+
|
127
|
+
excludes.map { |e| @command += ['--exclude', e] }
|
128
|
+
|
129
|
+
machine.ui.info(
|
130
|
+
I18n.t(
|
131
|
+
'vagrant.plugins.vagrant-reflect.rsync_folder_configuration',
|
132
|
+
guestpath: @guestpath,
|
133
|
+
hostpath: @hostpath))
|
134
|
+
if excludes.length > 1
|
135
|
+
machine.ui.info(
|
136
|
+
I18n.t(
|
137
|
+
'vagrant.plugins.vagrant-reflect.rsync_folder_excludes',
|
138
|
+
excludes: excludes.inspect))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def sync_incremental(items, &block)
|
143
|
+
command = @command.dup + [
|
144
|
+
'--files-from=-',
|
145
|
+
@hostpath,
|
146
|
+
@target,
|
147
|
+
{
|
148
|
+
workdir: @workdir,
|
149
|
+
notify: :stdin
|
150
|
+
}
|
151
|
+
]
|
152
|
+
|
153
|
+
current = false
|
154
|
+
r = Vagrant::Util::SubprocessPatched.execute(*command) do |what, io|
|
155
|
+
next if what != :stdin
|
156
|
+
|
157
|
+
current = process_items(io, items, current, &block)
|
158
|
+
end
|
159
|
+
|
160
|
+
check_exit command, r
|
161
|
+
end
|
162
|
+
|
163
|
+
def sync_full
|
164
|
+
command = @command.dup + [
|
165
|
+
@hostpath,
|
166
|
+
@target,
|
167
|
+
{
|
168
|
+
workdir: @workdir
|
169
|
+
}
|
170
|
+
]
|
171
|
+
|
172
|
+
r = Vagrant::Util::SubprocessPatched.execute(*command)
|
173
|
+
|
174
|
+
check_exit command, r
|
175
|
+
end
|
176
|
+
|
177
|
+
protected
|
178
|
+
|
179
|
+
def process_items(io, items, current, &block)
|
180
|
+
until items.empty?
|
181
|
+
# If we don't have a line, grab one and print it
|
182
|
+
if current === false
|
183
|
+
current = items.shift + "\n"
|
184
|
+
block.call(current) if block_given?
|
185
|
+
end
|
186
|
+
|
187
|
+
# Handle partial writes
|
188
|
+
n = io.write_nonblock(current)
|
189
|
+
if n < current.length
|
190
|
+
current = current[n..current.length]
|
191
|
+
break
|
192
|
+
end
|
193
|
+
|
194
|
+
# Request a new line for next write
|
195
|
+
current = false
|
196
|
+
end
|
197
|
+
|
198
|
+
# Finished! Close stdin
|
199
|
+
io.close_write
|
200
|
+
rescue IO::WaitWritable, Errno::EINTR
|
201
|
+
# Ignore
|
202
|
+
end
|
203
|
+
|
204
|
+
def check_exit(command, r)
|
205
|
+
return if r.exit_code == 0
|
206
|
+
|
207
|
+
raise Vagrant::Errors::RSyncError,
|
208
|
+
command: command.join(' '),
|
209
|
+
guestpath: @guestpath,
|
210
|
+
hostpath: @hostpath,
|
211
|
+
stderr: r.stderr
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
data/templates/locales/en.yml
CHANGED
@@ -16,20 +16,20 @@ en:
|
|
16
16
|
Watching: %{path}
|
17
17
|
rsync_auto_increment: |-
|
18
18
|
Sending change: %{path}
|
19
|
-
|
19
|
+
rsync_auto_full_change: |-
|
20
20
|
Processing change: %{path}
|
21
|
-
|
21
|
+
rsync_auto_full_remove: |-
|
22
22
|
Processing removal: %{path}
|
23
|
+
rsync_auto_full: |-
|
24
|
+
Performing full synchronisation due to removals
|
23
25
|
rsync_auto_synced: |-
|
24
26
|
Synchronization completed
|
25
27
|
rsync_communicator_not_ready_callback: |-
|
26
28
|
Failed to connect to remote machine. This is usually caused by the
|
27
29
|
machine rebooting or being halted. Please make sure the machine is
|
28
30
|
running, and modify a file to try again.
|
29
|
-
|
30
|
-
|
31
|
-
rsync_folder_changes: |-
|
32
|
-
Rsyncing changes only: %{hostpath} => %{guestpath}
|
31
|
+
rsync_folder_configuration: |-
|
32
|
+
Configuring rsync: %{hostpath} => %{guestpath}
|
33
33
|
rsync_folder_excludes: " - Exclude: %{excludes}"
|
34
34
|
rsync_proxy_machine: |-
|
35
35
|
The provider ('%{provider}') for the machine '%{name}' is
|
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.3.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-03-
|
11
|
+
date: 2016-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: driskell-listen
|
@@ -33,9 +33,9 @@ extra_rdoc_files: []
|
|
33
33
|
files:
|
34
34
|
- lib/vagrant-reflect.rb
|
35
35
|
- lib/vagrant-reflect/command/reflect.rb
|
36
|
-
- lib/vagrant-reflect/helper.rb
|
37
36
|
- lib/vagrant-reflect/patched/subprocess.rb
|
38
37
|
- lib/vagrant-reflect/plugin.rb
|
38
|
+
- lib/vagrant-reflect/util/syncer.rb
|
39
39
|
- lib/vagrant-reflect/version.rb
|
40
40
|
- templates/locales/en.yml
|
41
41
|
homepage: https://github.com/driskell/vagrant-reflect
|
@@ -1,169 +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 SyncHelper
|
9
|
-
# This converts an rsync exclude pattern to a regular expression
|
10
|
-
# we can send to Listen.
|
11
|
-
def self.exclude_to_regexp(path, exclude)
|
12
|
-
start_anchor = false
|
13
|
-
|
14
|
-
if exclude.start_with?('/')
|
15
|
-
start_anchor = true
|
16
|
-
exclude = exclude[1..-1]
|
17
|
-
end
|
18
|
-
|
19
|
-
path = "#{path}/" unless path.end_with?('/')
|
20
|
-
regexp = "^#{Regexp.escape(path)}"
|
21
|
-
regexp += '.*' unless start_anchor
|
22
|
-
|
23
|
-
# This is REALLY ghetto, but its a start. We can improve and
|
24
|
-
# keep unit tests passing in the future.
|
25
|
-
exclude = exclude.gsub('**', '|||GLOBAL|||')
|
26
|
-
exclude = exclude.gsub('*', '|||PATH|||')
|
27
|
-
exclude = exclude.gsub('|||PATH|||', '[^/]*')
|
28
|
-
exclude = exclude.gsub('|||GLOBAL|||', '.*')
|
29
|
-
regexp += exclude
|
30
|
-
|
31
|
-
Regexp.new(regexp)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.sync_single(machine, ssh_info, opts, &block)
|
35
|
-
# Folder info
|
36
|
-
guestpath = opts[:guestpath]
|
37
|
-
hostpath = opts[:hostpath]
|
38
|
-
hostpath = File.expand_path(hostpath, machine.env.root_path)
|
39
|
-
hostpath = Vagrant::Util::Platform.fs_real_path(hostpath).to_s
|
40
|
-
|
41
|
-
if Vagrant::Util::Platform.windows?
|
42
|
-
# rsync for Windows expects cygwin style paths, always.
|
43
|
-
hostpath = Vagrant::Util::Platform.cygwin_path(hostpath)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Make sure the host path ends with a "/" to avoid creating
|
47
|
-
# a nested directory...
|
48
|
-
hostpath += '/' unless hostpath.end_with?('/')
|
49
|
-
|
50
|
-
# Folder options
|
51
|
-
opts[:owner] ||= ssh_info[:username]
|
52
|
-
opts[:group] ||= ssh_info[:username]
|
53
|
-
|
54
|
-
# Connection information
|
55
|
-
username = ssh_info[:username]
|
56
|
-
host = ssh_info[:host]
|
57
|
-
proxy_command = ''
|
58
|
-
if ssh_info[:proxy_command]
|
59
|
-
proxy_command = "-o ProxyCommand='#{ssh_info[:proxy_command]}' "
|
60
|
-
end
|
61
|
-
|
62
|
-
rsh = [
|
63
|
-
"ssh -p #{ssh_info[:port]} " +
|
64
|
-
proxy_command +
|
65
|
-
'-o StrictHostKeyChecking=no '\
|
66
|
-
'-o IdentitiesOnly=true '\
|
67
|
-
'-o UserKnownHostsFile=/dev/null',
|
68
|
-
ssh_info[:private_key_path].map { |p| "-i '#{p}'" }
|
69
|
-
].flatten.join(' ')
|
70
|
-
|
71
|
-
# Exclude some files by default, and any that might be configured
|
72
|
-
# by the user.
|
73
|
-
excludes = ['.vagrant/']
|
74
|
-
excludes += Array(opts[:exclude]).map(&:to_s) if opts[:exclude]
|
75
|
-
excludes.uniq!
|
76
|
-
|
77
|
-
# Get the command-line arguments
|
78
|
-
args = nil
|
79
|
-
args = Array(opts[:args]).dup if opts[:args]
|
80
|
-
args ||= ['--verbose', '--archive', '--delete', '-z', '--copy-links']
|
81
|
-
|
82
|
-
# On Windows, we have to set a default chmod flag to avoid permission
|
83
|
-
# issues
|
84
|
-
if Vagrant::Util::Platform.windows?
|
85
|
-
unless args.any? { |arg| arg.start_with?('--chmod=') }
|
86
|
-
# Ensures that all non-masked bits get enabled
|
87
|
-
args << '--chmod=ugo=rwX'
|
88
|
-
|
89
|
-
# Remove the -p option if --archive is enabled (--archive equals
|
90
|
-
# -rlptgoD) otherwise new files will not have the destination-default
|
91
|
-
# permissions
|
92
|
-
args << '--no-perms' if
|
93
|
-
args.include?('--archive') || args.include?('-a')
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Disable rsync's owner/group preservation (implied by --archive) unless
|
98
|
-
# specifically requested, since we adjust owner/group to match shared
|
99
|
-
# folder setting ourselves.
|
100
|
-
args << '--no-owner' unless
|
101
|
-
args.include?('--owner') || args.include?('-o')
|
102
|
-
args << '--no-group' unless
|
103
|
-
args.include?('--group') || args.include?('-g')
|
104
|
-
|
105
|
-
# Tell local rsync how to invoke remote rsync with sudo
|
106
|
-
if machine.guest.capability?(:rsync_command)
|
107
|
-
args << '--rsync-path' << machine.guest.capability(:rsync_command)
|
108
|
-
end
|
109
|
-
|
110
|
-
args << '--files-from=-' if opts[:from_stdin] && block_given?
|
111
|
-
|
112
|
-
# Build up the actual command to execute
|
113
|
-
command = [
|
114
|
-
'rsync',
|
115
|
-
args,
|
116
|
-
'-e', rsh,
|
117
|
-
excludes.map { |e| ['--exclude', e] },
|
118
|
-
hostpath,
|
119
|
-
"#{username}@#{host}:#{guestpath}"
|
120
|
-
].flatten
|
121
|
-
|
122
|
-
# The working directory should be the root path
|
123
|
-
command_opts = {}
|
124
|
-
command_opts[:workdir] = machine.env.root_path.to_s
|
125
|
-
command_opts[:notify] = [:stdin] if opts[:from_stdin] && block_given?
|
126
|
-
|
127
|
-
if opts[:from_stdin] && block_given?
|
128
|
-
machine.ui.info(
|
129
|
-
I18n.t(
|
130
|
-
'vagrant.plugins.vagrant-reflect.rsync_folder_changes',
|
131
|
-
guestpath: guestpath,
|
132
|
-
hostpath: hostpath))
|
133
|
-
else
|
134
|
-
machine.ui.info(
|
135
|
-
I18n.t(
|
136
|
-
'vagrant.plugins.vagrant-reflect.rsync_folder',
|
137
|
-
guestpath: guestpath,
|
138
|
-
hostpath: hostpath))
|
139
|
-
end
|
140
|
-
if excludes.length > 1
|
141
|
-
machine.ui.info(
|
142
|
-
I18n.t(
|
143
|
-
'vagrant.plugins.vagrant-reflect.rsync_folder_excludes',
|
144
|
-
excludes: excludes.inspect))
|
145
|
-
end
|
146
|
-
|
147
|
-
# If we have tasks to do before rsyncing, do those.
|
148
|
-
if machine.guest.capability?(:rsync_pre)
|
149
|
-
machine.guest.capability(:rsync_pre, opts)
|
150
|
-
end
|
151
|
-
|
152
|
-
r = Vagrant::Util::SubprocessPatched.execute(*(command + [command_opts]), &block)
|
153
|
-
if r.exit_code != 0
|
154
|
-
raise Vagrant::Errors::RSyncError,
|
155
|
-
command: command.join(' '),
|
156
|
-
guestpath: guestpath,
|
157
|
-
hostpath: hostpath,
|
158
|
-
stderr: r.stderr
|
159
|
-
end
|
160
|
-
|
161
|
-
# If we have tasks to do after rsyncing, do those.
|
162
|
-
# REMOVE THESE - it triggers for VirtualBox an expensive find command that
|
163
|
-
# changes ownership, but we don't believe this is necessary
|
164
|
-
# if machine.guest.capability?(:rsync_post)
|
165
|
-
# machine.guest.capability(:rsync_post, opts)
|
166
|
-
# end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|