Module: Vagrant::Action::Builtin::MixinSyncedFolders

Includes:
Util::ScopedHashOverride
Included in:
SyncedFolderCleanup, SyncedFolders, Machine
Defined in:
lib/vagrant/action/builtin/mixin_synced_folders.rb

Instance Method Summary collapse

Methods included from Util::ScopedHashOverride

#scoped_hash_override

Instance Method Details

#default_synced_folder_type(machine, plugins) ⇒ Object

This goes over all the registered synced folder types and returns the highest priority implementation that is usable for this machine.


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/vagrant/action/builtin/mixin_synced_folders.rb', line 14

def default_synced_folder_type(machine, plugins)
  ordered = []

  # First turn the plugins into an array
  plugins.each do |key, data|
    impl     = data[0]
    priority = data[1]

    ordered << [priority, key, impl]
  end

  # Order the plugins by priority. Higher is tried before lower.
  ordered = ordered.sort { |a, b| b[0] <=> a[0] }

  allowed_types = machine.config.vm.allowed_synced_folder_types
  if allowed_types
    ordered = allowed_types.map do |type|
      ordered.find do |_, key, impl|
        key == type
      end
    end.compact
  end

  # Find the proper implementation
  ordered.each do |_, key, impl|
    return key if impl.new.usable?(machine)
  end

  return nil
end

#impl_opts(name, env) ⇒ Object

This finds the options in the env that are set for a given synced folder type.


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/vagrant/action/builtin/mixin_synced_folders.rb', line 47

def impl_opts(name, env)
  {}.tap do |result|
    env.each do |k, v|
      if k.to_s.start_with?("#{name}_")
        # While I generally don't like the 'rescue' syntax,
        # we do this to just fall back to the default value
        # if it isn't dup-able.
        k = k.dup rescue k
        v = v.dup rescue v

        result[k] = v
      end
    end
  end
end

#pluginsObject

This returns the available synced folder implementations. This is a separate method so that it can be easily stubbed by tests.


65
66
67
# File 'lib/vagrant/action/builtin/mixin_synced_folders.rb', line 65

def plugins
  @plugins ||= Vagrant.plugin("2").manager.synced_folders
end

#save_synced_folders(machine, folders, opts = {}) ⇒ Object

This saves the synced folders data to the machine data directory. They can then be retrieved again with synced_folders by passing the cached option to it.

Parameters:

  • machine (Machine)

    The machine that the folders belong to

  • folders (Hash)

    The result from a #synced_folders call.


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/vagrant/action/builtin/mixin_synced_folders.rb', line 75

def save_synced_folders(machine, folders, opts={})
  if opts[:merge]
    existing = cached_synced_folders(machine)
    if existing
      if opts[:vagrantfile]
        # Go through and find any cached that were from the
        # Vagrantfile itself. We remove those if it was requested.
        existing.each do |impl, fs|
          fs.each do |id, data|
            fs.delete(id) if data[:__vagrantfile]
          end
        end
      end

      folders.each do |impl, fs|
        existing[impl] ||= {}
        fs.each do |id, data|
          existing[impl][id] = data
        end
      end

      folders = existing
    end
  end

  # Remove implementation instances
  folder_data = JSON.dump(folders.to_h)

  machine.data_dir.join("synced_folders").open("w") do |f|
    f.write(folder_data)
  end
end

#synced_folders(machine, **opts) ⇒ Hash<Symbol, Hash<String, Hash>>

This returns the set of shared folders that should be done for this machine. It returns the folders in a hash keyed by the implementation class for the synced folders.

Returns:

  • (Hash<Symbol, Hash<String, Hash>>)

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/vagrant/action/builtin/mixin_synced_folders.rb', line 113

def synced_folders(machine, **opts)
  return cached_synced_folders(machine) if opts[:cached]

  config = opts[:config]
  root   = false
  if !config
    config = machine.config.vm
    root   = true
  end

  config_folders = config.synced_folders
  folders = Vagrant::Plugin::V2::SyncedFolder::Collection.new

  # Determine all the synced folders as well as the implementation
  # they're going to use.
  config_folders.each do |id, data|
    # Ignore disabled synced folders
    next if data[:disabled]

    impl = ""
    impl = data[:type].to_sym if data[:type] && !data[:type].empty?

    if impl != ""
      impl_class = plugins[impl]
      if !impl_class
        # This should never happen because configuration validation
        # should catch this case. But we put this here as an assert
        raise "Internal error. Report this as a bug. Invalid: #{data[:type]}"
      end

      if !opts[:disable_usable_check]
        if !impl_class[0].new.usable?(machine, true)
          # Verify that explicitly defined shared folder types are
          # actually usable.
          raise Errors::SyncedFolderUnusable, type: data[:type].to_s
        end
      end
    end

    # Get the data to store
    data = data.dup
    if root
      # If these are the root synced folders (attached directly)
      # to the Vagrantfile, then we mark it as such.
      data[:__vagrantfile] = true
    end

    # Keep track of this shared folder by the implementation.
    folders[impl] ||= {}
    folders[impl][id] = data
  end

  # If we have folders with the "default" key, then determine the
  # most appropriate implementation for this.
  if folders.key?("") && !folders[""].empty?
    default_impl = default_synced_folder_type(machine, plugins)
    if !default_impl
      types = plugins.to_hash.keys.map { |t| t.to_s }.sort.join(", ")
      raise Errors::NoDefaultSyncedFolderImpl, types: types
    end

    folders[default_impl] ||= {}
    folders[default_impl].merge!(folders[""])
    folders.delete("")
  end

  # Apply the scoped hash overrides to get the options
  folders.dup.each do |impl_name, fs|
    impl = plugins[impl_name].first.new._initialize(machine, impl_name)
    new_fs = {}
    fs.each do |id, data|
      data[:plugin] = impl
      id         = data[:id] if data[:id]
      new_fs[id] = scoped_hash_override(data, impl_name)
    end

    folders[impl_name] = new_fs
  end

  folders
end

#synced_folders_diff(one, two) ⇒ hash

This finds the difference between two lists of synced folder definitions.

This will return a hash with three keys: "added", "removed", and "modified". These will contain a set of IDs of folders that were added, removed, or modified, respectively.

The parameters should be results from the #synced_folders call.

Returns:

  • (hash)

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/vagrant/action/builtin/mixin_synced_folders.rb', line 205

def synced_folders_diff(one, two)
  existing_ids = {}
  one.each do |impl, fs|
    fs.each do |id, data|
      existing_ids[id] = data
    end
  end

  result = Hash.new { |h, k| h[k] = Set.new }
  two.each do |impl, fs|
    fs.each do |id, data|
      existing = existing_ids.delete(id)
      if !existing
        result[:added] << id
        next
      end

      # Exists, so we have to compare the host and guestpath, which
      # is most important...
      if existing[:hostpath] != data[:hostpath] ||
        existing[:guestpath] != data[:guestpath]
        result[:modified] << id
      end
    end
  end

  existing_ids.each do |k, _|
    result[:removed] << k
  end

  result
end