vagrant-mirror 0.1.1.alpha → 0.1.2.alpha
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.
- 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
|