vagrant-mirror 0.1.1.alpha → 0.1.2.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +0 -5
- data/lib/vagrant-mirror/listener/host.rb +14 -6
- data/lib/vagrant-mirror/middleware/base.rb +6 -3
- data/lib/vagrant-mirror/middleware/mirror.rb +86 -28
- data/lib/vagrant-mirror/middleware/sync.rb +1 -17
- data/lib/vagrant-mirror/version.rb +1 -1
- data/spec/vagrant-mirror/listener/host_spec.rb +21 -15
- data/spec/vagrant-mirror/middleware/mirror_spec.rb +92 -26
- metadata +2 -2
data/Gemfile.lock
CHANGED
@@ -14,7 +14,6 @@ GEM
|
|
14
14
|
coderay (1.0.8)
|
15
15
|
diff-lcs (1.1.3)
|
16
16
|
erubis (2.7.0)
|
17
|
-
ffi (1.2.0)
|
18
17
|
ffi (1.2.0-x86-mingw32)
|
19
18
|
guard (1.6.1)
|
20
19
|
listen (>= 0.6.0)
|
@@ -33,10 +32,6 @@ GEM
|
|
33
32
|
net-scp (1.0.4)
|
34
33
|
net-ssh (>= 1.99.1)
|
35
34
|
net-ssh (2.2.2)
|
36
|
-
pry (0.9.10)
|
37
|
-
coderay (~> 1.0.5)
|
38
|
-
method_source (~> 0.8)
|
39
|
-
slop (~> 3.3.1)
|
40
35
|
pry (0.9.10-x86-mingw32)
|
41
36
|
coderay (~> 1.0.5)
|
42
37
|
method_source (~> 0.8)
|
@@ -18,12 +18,20 @@ module Vagrant
|
|
18
18
|
# Makes a blocking call to Guard to listen on the configured path
|
19
19
|
def listen!
|
20
20
|
Listen.to(@path, :relative_paths => true) do | modified, added, removed |
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
:
|
25
|
-
|
26
|
-
|
21
|
+
|
22
|
+
# Add each reported file to the queue
|
23
|
+
modified.each do | path |
|
24
|
+
@queue << { :event => :modified, :path => path }
|
25
|
+
end
|
26
|
+
|
27
|
+
added.each do | path |
|
28
|
+
@queue << { :event => :added, :path => path }
|
29
|
+
end
|
30
|
+
|
31
|
+
removed.each do | path |
|
32
|
+
@queue << { :event => :removed, :path => path }
|
33
|
+
end
|
34
|
+
|
27
35
|
end
|
28
36
|
end
|
29
37
|
|
@@ -15,18 +15,21 @@ module Vagrant
|
|
15
15
|
@env = env
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
#
|
18
|
+
# Loads the rest of the middlewares first, then finishes up by running
|
19
|
+
# our middleware. This is required because the core share_folders and
|
20
|
+
# provision middlewares don not mount the shares until the very end of
|
21
|
+
# the process and we need to run after that
|
20
22
|
#
|
21
23
|
# @param [Vagrant::Action::Environment] The environment
|
22
24
|
def call(env)
|
25
|
+
@app.call(env)
|
26
|
+
|
23
27
|
mirrors = env[:vm].config.mirror.folders
|
24
28
|
if !mirrors.empty?
|
25
29
|
execute(mirrors, env)
|
26
30
|
else
|
27
31
|
env[:ui].info("No vagrant-mirror mirrored folders configured for this box")
|
28
32
|
end
|
29
|
-
@app.call(env)
|
30
33
|
end
|
31
34
|
|
32
35
|
protected
|
@@ -8,22 +8,6 @@ module Vagrant
|
|
8
8
|
module Middleware
|
9
9
|
class Mirror < Base
|
10
10
|
|
11
|
-
# Loads the rest of the middlewares first, then finishes up by running
|
12
|
-
# the mirror middleware. This allows the listener to start after the
|
13
|
-
# instance has been provisioned.
|
14
|
-
#
|
15
|
-
# @param [Vagrant::Action::Environment] The environment
|
16
|
-
def call(env)
|
17
|
-
@app.call(env)
|
18
|
-
|
19
|
-
mirrors = env[:vm].config.mirror.folders
|
20
|
-
if !mirrors.empty?
|
21
|
-
execute(mirrors, env)
|
22
|
-
else
|
23
|
-
env[:ui].info("No vagrant-mirror mirrored folders configured for this box")
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
11
|
protected
|
28
12
|
|
29
13
|
# Mirrors the folder pairs configured in the vagrantfile
|
@@ -31,6 +15,7 @@ module Vagrant
|
|
31
15
|
# @param [Array] The folder pairs to synchronise
|
32
16
|
# @param [Vagrant::Action::Environment] The environment
|
33
17
|
def execute(mirrors, env)
|
18
|
+
|
34
19
|
ui = env[:ui]
|
35
20
|
ui.info("Beginning directory mirroring")
|
36
21
|
|
@@ -55,26 +40,34 @@ module Vagrant
|
|
55
40
|
if (change[:quit])
|
56
41
|
quit = true
|
57
42
|
else
|
43
|
+
# Ignore files that match the configured exclude paths
|
44
|
+
if exclude?(change[:path], mirror_config)
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
58
48
|
# Handle removed files first - guard sometimes flagged as deleted when they aren't
|
59
49
|
# So we first check if the file has been deleted on the host. If so, we delete on
|
60
50
|
# the guest, otherwise we add to the list to rsync in case there are changes
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
else
|
66
|
-
target = "#{mirror_config[:guest_path]}/#{relpath}"
|
51
|
+
if (change[:event] == :removed)
|
52
|
+
unless File.exists?(File.join(host_path, change[:path]))
|
53
|
+
# Delete the file on the guest
|
54
|
+
target = "#{mirror_config[:guest_path]}/#{change[:path]}"
|
67
55
|
ui.warn("XX Deleting #{target}")
|
68
56
|
env[:vm].channel.sudo("rm #{target}")
|
57
|
+
|
58
|
+
# Beep if configured
|
59
|
+
if (mirror_config[:beep])
|
60
|
+
print "\a"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Move to the next file
|
64
|
+
next
|
69
65
|
end
|
70
66
|
end
|
71
67
|
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
ui.info(">> #{relpath}")
|
76
|
-
rsync.run(relpath)
|
77
|
-
end
|
68
|
+
# Otherwise, run rsync on the file
|
69
|
+
ui.info(">> #{change[:path]}")
|
70
|
+
rsync.run(change[:path])
|
78
71
|
|
79
72
|
# Beep if configured
|
80
73
|
if (mirror_config[:beep])
|
@@ -102,6 +95,71 @@ module Vagrant
|
|
102
95
|
ui.success("Completed directory synchronisation")
|
103
96
|
end
|
104
97
|
|
98
|
+
# Checks whether a given path should be excluded based on the :exclude config for this mirror
|
99
|
+
#
|
100
|
+
# @param [String] The file path being processed
|
101
|
+
# @param [Hash] The mirror config options
|
102
|
+
#
|
103
|
+
# @return [Bool] Whether to exclude this file
|
104
|
+
def exclude?(path, mirror_config)
|
105
|
+
compiled_excludes = mirror_config.fetch(:compiled_excludes, {})
|
106
|
+
excluded = false
|
107
|
+
|
108
|
+
mirror_config[:exclude].each do | exclude |
|
109
|
+
# Check if it has been compiled
|
110
|
+
unless compiled_excludes.has_key? exclude
|
111
|
+
compiled_excludes[exclude] = compile_exclude(exclude)
|
112
|
+
end
|
113
|
+
exclude = compiled_excludes[exclude]
|
114
|
+
|
115
|
+
# Test for a match against the path
|
116
|
+
if exclude.match(path)
|
117
|
+
excluded = true
|
118
|
+
break
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Return the result
|
123
|
+
excluded
|
124
|
+
end
|
125
|
+
|
126
|
+
# Mirrors the folder pairs configured in the vagrantfile
|
127
|
+
#
|
128
|
+
# @param [String] A glob-style exclude format
|
129
|
+
#
|
130
|
+
# @return [Regexp] The exclude path as a regex
|
131
|
+
def compile_exclude(exclude)
|
132
|
+
exclude = exclude.dup
|
133
|
+
|
134
|
+
# Absolute path is tied to start of string, relative to any directory separator
|
135
|
+
if exclude.chars.first == '/'
|
136
|
+
regex = "^"
|
137
|
+
exclude[0] = ''
|
138
|
+
else
|
139
|
+
regex = "(^|/)"
|
140
|
+
end
|
141
|
+
|
142
|
+
# Temporarily convert wildcards to placeholders
|
143
|
+
exclude.sub!('**','<<globwild2>>')
|
144
|
+
exclude.sub!('*','<<globwild>>')
|
145
|
+
|
146
|
+
# Escape the string for regexp characters
|
147
|
+
exclude = Regexp.escape(exclude)
|
148
|
+
|
149
|
+
|
150
|
+
# one star matches anything except directories
|
151
|
+
exclude.sub!('<<globwild>>', '[^/]*?')
|
152
|
+
|
153
|
+
# two stars match anything including directories
|
154
|
+
exclude.sub!('<<globwild2>>','.*?')
|
155
|
+
|
156
|
+
regex << exclude
|
157
|
+
|
158
|
+
# pattern should always end on a directory separator or end of string
|
159
|
+
regex << '($|/)'
|
160
|
+
|
161
|
+
Regexp.new(regex)
|
162
|
+
end
|
105
163
|
end
|
106
164
|
end
|
107
165
|
end
|
@@ -10,23 +10,6 @@ module Vagrant
|
|
10
10
|
module Middleware
|
11
11
|
class Sync < Base
|
12
12
|
|
13
|
-
# Loads the rest of the middlewares first, then finishes up by running
|
14
|
-
# the sync middleware. This is required because the core share_folders
|
15
|
-
# middleware does not mount the shares until the very end of the process
|
16
|
-
# and we need to run after that
|
17
|
-
#
|
18
|
-
# @param [Vagrant::Action::Environment] The environment
|
19
|
-
def call(env)
|
20
|
-
@app.call(env)
|
21
|
-
|
22
|
-
mirrors = env[:vm].config.mirror.folders
|
23
|
-
if !mirrors.empty?
|
24
|
-
execute(mirrors, env)
|
25
|
-
else
|
26
|
-
env[:ui].info("No vagrant-mirror mirrored folders configured for this box")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
13
|
protected
|
31
14
|
|
32
15
|
# Synchronizes the folder pairs configured in the vagrantfile
|
@@ -75,6 +58,7 @@ module Vagrant
|
|
75
58
|
rsync.run('/')
|
76
59
|
end
|
77
60
|
|
61
|
+
|
78
62
|
rescue RuntimeError => e
|
79
63
|
# Pass through Vagrant errors
|
80
64
|
if e.is_a? Vagrant::Errors::VagrantError
|
@@ -26,40 +26,46 @@ describe Vagrant::Mirror::Listener::Host do
|
|
26
26
|
context "when changes received" do
|
27
27
|
before(:each) do
|
28
28
|
Listen.stub(:to)
|
29
|
-
.and_yield(['
|
30
|
-
.and_yield([],['
|
31
|
-
.and_yield([],[],['
|
32
|
-
.and_yield(['
|
29
|
+
.and_yield(['modified1','modified2'],[],[])
|
30
|
+
.and_yield([],['added1','added2'],[])
|
31
|
+
.and_yield([],[],['removed1','removed2'])
|
32
|
+
.and_yield(['modified3'],['added3'],['removed3'])
|
33
33
|
end
|
34
34
|
|
35
|
-
it "pushes added files onto the queue" do
|
35
|
+
it "pushes added files onto the queue one by one" do
|
36
36
|
queue.should_receive(:"<<")
|
37
|
-
.with(hash_including(:added =>
|
37
|
+
.with(hash_including({:event => :added, :path => 'added1'}))
|
38
|
+
queue.should_receive(:"<<")
|
39
|
+
.with(hash_including({:event => :added, :path => 'added2'}))
|
38
40
|
|
39
41
|
subject.listen!
|
40
42
|
end
|
41
43
|
|
42
|
-
it "pushes modified files onto the queue" do
|
44
|
+
it "pushes modified files onto the queue one by one" do
|
45
|
+
queue.should_receive(:"<<")
|
46
|
+
.with(hash_including({:event => :modified, :path => 'modified1'}))
|
43
47
|
queue.should_receive(:"<<")
|
44
|
-
.with(hash_including(:modified =>
|
48
|
+
.with(hash_including({:event => :modified, :path => 'modified2'}))
|
45
49
|
|
46
50
|
subject.listen!
|
47
51
|
end
|
48
52
|
|
49
|
-
it "pushes removed files onto the queue" do
|
53
|
+
it "pushes removed files onto the queue one by one" do
|
54
|
+
queue.should_receive(:"<<")
|
55
|
+
.with(hash_including({:event => :removed, :path => 'removed1'}))
|
50
56
|
queue.should_receive(:"<<")
|
51
|
-
.with(hash_including(:removed =>
|
57
|
+
.with(hash_including({:event => :removed, :path => 'removed2'}))
|
52
58
|
|
53
59
|
subject.listen!
|
54
60
|
end
|
55
61
|
|
56
62
|
it "handles simultaneous changes" do
|
57
63
|
queue.should_receive(:"<<")
|
58
|
-
.with(hash_including({
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
64
|
+
.with(hash_including({:event => :added, :path => 'added3'}))
|
65
|
+
queue.should_receive(:"<<")
|
66
|
+
.with(hash_including({:event => :modified, :path => 'modified3'}))
|
67
|
+
queue.should_receive(:"<<")
|
68
|
+
.with(hash_including({:event => :removed, :path => 'removed3'}))
|
63
69
|
|
64
70
|
subject.listen!
|
65
71
|
end
|
@@ -54,9 +54,10 @@ describe Vagrant::Mirror::Middleware::Mirror do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
context "with a mirrored folder" do
|
57
|
+
let ( :mirror_options ) { {} }
|
57
58
|
|
58
59
|
before (:each) do
|
59
|
-
config.mirror.vagrant_root '/var/guest'
|
60
|
+
config.mirror.vagrant_root '/var/guest', mirror_options
|
60
61
|
config.vm.share_folder("v-root", "/vagrant", ".")
|
61
62
|
end
|
62
63
|
|
@@ -122,50 +123,115 @@ describe Vagrant::Mirror::Middleware::Mirror do
|
|
122
123
|
|
123
124
|
context "with notifications in the queue" do
|
124
125
|
|
125
|
-
let (:added)
|
126
|
-
let (:modified)
|
127
|
-
let (:
|
128
|
-
let (:
|
126
|
+
let (:added) { { :event => :added, :path => 'added' } }
|
127
|
+
let (:modified) { { :event => :modified, :path => 'modified'} }
|
128
|
+
let (:removed_exists) { { :event => :removed, :path => 'removed_exists'}}
|
129
|
+
let (:removed_remvd) { { :event => :removed, :path => 'removed_remvd'}}
|
129
130
|
|
130
131
|
before (:each) do
|
131
132
|
queue.stub(:pop).and_return(
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
added,
|
134
|
+
modified,
|
135
|
+
removed_exists,
|
136
|
+
removed_remvd,
|
137
|
+
{ :quit => true }
|
138
|
+
)
|
139
|
+
|
140
|
+
File.stub(:exists?).with("#{env[:root_path]}/removed_exists").and_return(true)
|
141
|
+
File.stub(:exists?).with("#{env[:root_path]}/removed_remvd").and_return(false)
|
136
142
|
end
|
137
143
|
|
138
144
|
it "runs rsync one by one for each added and modified file" do
|
139
145
|
rsync.should_receive(:run).with("added")
|
140
146
|
rsync.should_receive(:run).with("modified")
|
141
|
-
rsync.should_receive(:run).with("modified2")
|
142
147
|
|
143
148
|
subject.call(env)
|
144
149
|
sleep 0.2
|
145
150
|
end
|
146
151
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
152
|
+
it "deletes files by SSH if they have been deleted on the host" do
|
153
|
+
channel.should_receive(:sudo).with('rm /var/guest/removed_remvd')
|
154
|
+
|
155
|
+
subject.call(env)
|
156
|
+
sleep 0.2
|
157
|
+
end
|
158
|
+
|
159
|
+
it "runs rsync to update deleted files if they still exist on the host" do
|
160
|
+
rsync.should_receive(:run).with('removed_exists')
|
161
|
+
|
162
|
+
subject.call(env)
|
163
|
+
sleep 0.2
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "with notifications in the queue when exclude paths are configured" do
|
168
|
+
let (:mirror_options) { { :exclude => [ "/docs", "cache", "*.png", "dir*", "/vendor/**/test"] } }
|
169
|
+
|
170
|
+
# For these tests we want to know about unexpected calls
|
171
|
+
let (:rsync) { double("Vagrant::Mirror::Rsync") }
|
172
|
+
|
173
|
+
it "correctly filters absolute paths within the sync folder" do
|
174
|
+
queue.stub(:pop).and_return(
|
175
|
+
{ :event => :added, :path => "docs/should/ignore.fl" },
|
176
|
+
{ :event => :added, :path => "should/not/ignore/docs.txt" },
|
177
|
+
{ :quit => true })
|
178
|
+
|
179
|
+
rsync.should_receive(:run).with('should/not/ignore/docs.txt')
|
180
|
+
|
181
|
+
subject.call(env)
|
182
|
+
sleep 0.2
|
183
|
+
end
|
184
|
+
|
185
|
+
it "correctly filters named directories within the sync folder" do
|
186
|
+
queue.stub(:pop).and_return(
|
187
|
+
{ :event => :added, :path => "cache/should/ignore.fl" },
|
188
|
+
{ :event => :added, :path => "should/cache/ignore.fl" },
|
189
|
+
{ :event => :added, :path => "cacheit/should/not/ignore.fl" },
|
190
|
+
{ :quit => true })
|
191
|
+
|
192
|
+
rsync.should_receive(:run).with('cacheit/should/not/ignore.fl')
|
193
|
+
|
194
|
+
subject.call(env)
|
195
|
+
sleep 0.2
|
196
|
+
end
|
197
|
+
|
198
|
+
it "correctly filters filename wildcards" do
|
199
|
+
queue.stub(:pop).and_return(
|
200
|
+
{ :event => :added, :path => "ignore.png" },
|
201
|
+
{ :event => :added, :path => "should/ignore.png" },
|
202
|
+
{ :event => :added, :path => "should/not/png/ignore.txt" },
|
203
|
+
{ :quit => true })
|
151
204
|
|
152
|
-
|
153
|
-
channel.should_receive(:sudo).with('rm /var/guest/removed')
|
205
|
+
rsync.should_receive(:run).with('should/not/png/ignore.txt')
|
154
206
|
|
155
|
-
|
156
|
-
|
157
|
-
end
|
207
|
+
subject.call(env)
|
208
|
+
sleep 0.2
|
158
209
|
end
|
159
210
|
|
160
|
-
|
161
|
-
|
211
|
+
it "correctly filters glob patterns with *" do
|
212
|
+
queue.stub(:pop).and_return(
|
213
|
+
{ :event => :added, :path => "dir1/should/ignore.fl" },
|
214
|
+
{ :event => :added, :path => "should/dirignore/this.tst" },
|
215
|
+
{ :event => :added, :path => "should/notdir/ignore.tst" },
|
216
|
+
{ :quit => true })
|
217
|
+
|
218
|
+
rsync.should_receive(:run).with('should/notdir/ignore.tst')
|
162
219
|
|
163
|
-
|
164
|
-
|
220
|
+
subject.call(env)
|
221
|
+
sleep 0.2
|
222
|
+
end
|
165
223
|
|
166
|
-
|
167
|
-
|
168
|
-
|
224
|
+
it "correctly filters glob patterns with **" do
|
225
|
+
queue.stub(:pop).and_return(
|
226
|
+
{ :event => :added, :path => "vendor/my/test/file.tst" },
|
227
|
+
{ :event => :added, :path => "vendor/my/deep/test/file.tst" },
|
228
|
+
{ :event => :added, :path => "vendor/test/file.tst" },
|
229
|
+
{ :quit => true })
|
230
|
+
|
231
|
+
rsync.should_receive(:run).with('vendor/test/file.tst')
|
232
|
+
|
233
|
+
subject.call(env)
|
234
|
+
sleep 0.2
|
169
235
|
end
|
170
236
|
|
171
237
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-mirror
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2.alpha
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: vagrant
|