Class: Vagrant::Box

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/vagrant/box.rb

Overview

Represents a "box," which is a package Vagrant environment that is used as a base image when creating a new guest machine.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, provider, version, directory, **opts) ⇒ Box

This is used to initialize a box.

Parameters:

  • name (String)

    Logical name of the box.

  • provider (Symbol)

    The provider that this box implements.

  • directory (Pathname)

    The directory where this box exists on disk.

Raises:



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/vagrant/box.rb', line 57

def initialize(name, provider, version, directory, **opts)
  @name      = name
  @version   = version
  @provider  = provider
  @directory = directory
  @metadata_url = opts[:metadata_url]

   = directory.join("metadata.json")
  raise Errors::BoxMetadataFileNotFound, name: @name if !.file?

  begin
    @metadata = JSON.parse(directory.join("metadata.json").read)
  rescue JSON::ParserError
    raise Errors::BoxMetadataCorrupted, name: @name
  end

  @logger = Log4r::Logger.new("vagrant::box")
end

Instance Attribute Details

#directoryPathname (readonly)

This is the directory on disk where this box exists.

Returns:

  • (Pathname)


37
38
39
# File 'lib/vagrant/box.rb', line 37

def directory
  @directory
end

#metadataHash (readonly)

This is the metadata for the box. This is read from the "metadata.json" file that all boxes require.

Returns:

  • (Hash)


43
44
45
# File 'lib/vagrant/box.rb', line 43

def 
  @metadata
end

#metadata_urlString (readonly)

This is the URL to the version info and other metadata for this box.

Returns:

  • (String)


49
50
51
# File 'lib/vagrant/box.rb', line 49

def 
  @metadata_url
end

#nameString (readonly)

The box name. This is the logical name used when adding the box.

Returns:

  • (String)


22
23
24
# File 'lib/vagrant/box.rb', line 22

def name
  @name
end

#providerSymbol (readonly)

This is the provider that this box is built for.

Returns:

  • (Symbol)


27
28
29
# File 'lib/vagrant/box.rb', line 27

def provider
  @provider
end

#versionString (readonly)

The version of this box.

Returns:

  • (String)


32
33
34
# File 'lib/vagrant/box.rb', line 32

def version
  @version
end

Instance Method Details

#<=>(other) ⇒ Object

Implemented for comparison with other boxes. Comparison is implemented by comparing names and providers.



190
191
192
193
194
195
196
# File 'lib/vagrant/box.rb', line 190

def <=>(other)
  return super if !other.is_a?(self.class)

  # Comparison is done by composing the name and provider
  "#{@name}-#{@version}-#{@provider}" <=>
  "#{other.name}-#{other.version}-#{other.provider}"
end

#destroy!Object

This deletes the box. This is NOT undoable.



77
78
79
80
81
82
83
84
85
86
# File 'lib/vagrant/box.rb', line 77

def destroy!
  # Delete the directory to delete the box.
  FileUtils.rm_r(@directory)

  # Just return true always
  true
rescue Errno::ENOENT
  # This means the directory didn't exist. Not a problem.
  return true
end

#has_update?(version = nil, download_options: {}) ⇒ Array

Checks if the box has an update and returns the metadata, version, and provider. If the box doesn't have an update that satisfies the constraints, it will return nil.

This will potentially make a network call if it has to load the metadata from the network.

Parameters:

  • version (String) (defaults to: nil)

    Version constraints the update must satisfy. If nil, the version constrain defaults to being a larger version than this box.

Returns:

  • (Array)


152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/vagrant/box.rb', line 152

def has_update?(version=nil, download_options: {})
  if !@metadata_url
    raise Errors::BoxUpdateNoMetadata, name: @name
  end

  version += ", " if version
  version ||= ""
  version += "> #{@version}"
  md      = self.(download_options)
  newer   = md.version(version, provider: @provider)
  return nil if !newer

  [md, newer, newer.provider(@provider)]
end

#in_use?(index) ⇒ Array<MachineIndex::Entry>

Checks if this box is in use according to the given machine index and returns the entries that appear to be using the box.

The entries returned, if any, are not tested for validity with MachineIndex::Entry#valid?, so the caller should do that if the caller cares.

Parameters:

Returns:



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/vagrant/box.rb', line 97

def in_use?(index)
  results = []
  index.each do |entry|
    box_data = entry.extra_data["box"]
    next if !box_data

    # If all the data matches, record it
    if box_data["name"] == self.name &&
      box_data["provider"] == self.provider.to_s &&
      box_data["version"] == self.version.to_s
      results << entry
    end
  end

  return nil if results.empty?
  results
end

#load_metadata(**download_options) ⇒ BoxMetadata

Loads the metadata URL and returns the latest metadata associated with this box.

Parameters:

  • download_options (Hash)

    Options to pass to the downloader.

Returns:



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/vagrant/box.rb', line 120

def (**download_options)
  tf = Tempfile.new("vagrant-load-metadata")
  tf.close

  url = @metadata_url
  if File.file?(url) || url !~ /^[a-z0-9]+:.*$/i
    url = File.expand_path(url)
    url = Util::Platform.cygwin_windows_path(url)
    url = "file:#{url}"
  end

  opts = { headers: ["Accept: application/json"] }.merge(download_options)
  Util::Downloader.new(url, tf.path, **opts).download!
  BoxMetadata.new(File.open(tf.path, "r"))
rescue Errors::DownloaderError => e
  raise Errors::BoxMetadataDownloadError,
    message: e.extra_data[:message]
ensure
  tf.unlink if tf
end

#repackage(path) ⇒ Boolean

This repackages this box and outputs it to the given path.

Parameters:

  • path (Pathname)

    The full path (filename included) of where to output this box.

Returns:

  • (Boolean)

    true if this succeeds.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/vagrant/box.rb', line 172

def repackage(path)
  @logger.debug("Repackaging box '#{@name}' to: #{path}")

  Util::SafeChdir.safe_chdir(@directory) do
    # Find all the files in our current directory and tar it up!
    files = Dir.glob(File.join(".", "**", "*")).select { |f| File.file?(f) }

    # Package!
    Util::Subprocess.execute("bsdtar", "-czf", path.to_s, *files)
  end

  @logger.info("Repackaged box '#{@name}' successfully: #{path}")

  true
end