Class: Vagrant::Action::General::Package
- Inherits:
-
Object
- Object
- Vagrant::Action::General::Package
- Includes:
- Util
- Defined in:
- lib/vagrant/action/general/package.rb
Overview
A general packaging (tar) middleware. Given the following options, it will do the right thing:
- package.output - The filename of the outputted package.
- package.include - An array of files to include in the package.
- package.info - Path of desired info.json file to include
- package.directory - The directory which contains the contents to compress into the package.
This middleware always produces the final file in the current working directory (FileUtils.pwd)
Instance Attribute Summary collapse
-
#fullpath ⇒ String
readonly
The path to the final output file.
Class Method Summary collapse
-
.fullpath(output) ⇒ Object
Calculate the full path of the given path, relative to the current working directory (where the command was run).
-
.validate!(output, directory) ⇒ Object
Perform sanity validations that the provided output filepath is sane.
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#compress ⇒ Object
Compress the exported file into a package.
-
#copy_include_files ⇒ Object
This method copies the include files (passed in via command line) to the temporary directory so they are included in a sub-folder within the actual box.
-
#copy_info ⇒ Object
This method copies the specified info.json file to the temporary directory so that it is accessible via the 'box list -i' command.
- #create_box_folder(folder_path) ⇒ Object
-
#initialize(app, env) ⇒ Package
constructor
A new instance of Package.
-
#invalid_info? ⇒ Boolean
Check to see if package.info is a valid file and titled info.json.
- #package_with_folder_path ⇒ Object
- #recover(env) ⇒ Object
-
#setup_private_key ⇒ Object
This will copy the generated private key into the box and use it for SSH by default.
-
#write_metadata_json ⇒ Object
Write the metadata file into the box so that the provider can be automatically detected when adding the box.
Constructor Details
#initialize(app, env) ⇒ Package
Returns a new instance of Package.
65 66 67 68 69 70 71 72 73 |
# File 'lib/vagrant/action/general/package.rb', line 65 def initialize(app, env) @app = app env["package.files"] ||= {} env["package.info"] ||= "" env["package.output"] ||= "package.box" @fullpath = self.class.fullpath(env["package.output"]) end |
Instance Attribute Details
#fullpath ⇒ String (readonly)
The path to the final output file.
63 64 65 |
# File 'lib/vagrant/action/general/package.rb', line 63 def fullpath @fullpath end |
Class Method Details
.fullpath(output) ⇒ Object
Calculate the full path of the given path, relative to the current working directory (where the command was run).
57 58 59 |
# File 'lib/vagrant/action/general/package.rb', line 57 def self.fullpath(output) File.(output, Dir.pwd) end |
.validate!(output, directory) ⇒ Object
Perform sanity validations that the provided output filepath is sane. In particular, this function validates:
- The output path is a regular file (not a directory or symlink)
- No file currently exists at the given path
- A directory of package files was actually provided (internal)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/vagrant/action/general/package.rb', line 36 def self.validate!(output, directory) filename = File.basename(output.to_s) output = fullpath(output) if File.directory?(output) raise Vagrant::Errors::PackageOutputDirectory end if File.exist?(output) raise Vagrant::Errors::PackageOutputExists, filename: filename end if !Vagrant::Util::Presence.present?(directory) || !File.directory?(directory) raise Vagrant::Errors::PackageRequiresDirectory end end |
Instance Method Details
#call(env) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/vagrant/action/general/package.rb', line 75 def call(env) @env = env self.class.validate!(env["package.output"], env["package.directory"]) package_with_folder_path if env["package.output"].include?(File::SEPARATOR) raise Errors::PackageOutputDirectory if File.directory?(fullpath) raise Errors::PackageInvalidInfo if invalid_info? @app.call(env) @env[:ui].info I18n.t("vagrant.actions.general.package.compressing", fullpath: fullpath) copy_include_files copy_info setup_private_key compress end |
#compress ⇒ Object
Compress the exported file into a package
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/vagrant/action/general/package.rb', line 158 def compress # Get the output path. We have to do this up here so that the # pwd returns the proper thing. output_path = fullpath.to_s # Switch into that directory and package everything up Util::SafeChdir.safe_chdir(@env["package.directory"]) do # Find all the files in our current directory and tar it up! files = Dir.glob(File.join(".", "*")) # Package! Util::Subprocess.execute("bsdtar", "-czf", output_path, *files) end end |
#copy_include_files ⇒ Object
This method copies the include files (passed in via command line) to the temporary directory so they are included in a sub-folder within the actual box
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/vagrant/action/general/package.rb', line 123 def copy_include_files include_directory = Pathname.new(@env["package.directory"]).join("include") @env["package.files"].each do |from, dest| # We place the file in the include directory to = include_directory.join(dest) @env[:ui].info I18n.t("vagrant.actions.general.package.packaging", file: from) FileUtils.mkdir_p(to.parent) # Copy directory contents recursively. if File.directory?(from) FileUtils.cp_r(Dir.glob(from), to.parent, preserve: true) else FileUtils.cp(from, to, preserve: true) end end rescue Errno::EEXIST => e raise if !e.to_s.include?("symlink") # The directory contains symlinks. Show a nicer error. raise Errors::PackageIncludeSymlink end |
#copy_info ⇒ Object
This method copies the specified info.json file to the temporary directory so that it is accessible via the 'box list -i' command
149 150 151 152 153 154 155 |
# File 'lib/vagrant/action/general/package.rb', line 149 def copy_info info_path = Pathname.new(@env["package.info"]) if info_path.file? FileUtils.cp(info_path, @env["package.directory"], preserve: true) end end |
#create_box_folder(folder_path) ⇒ Object
102 103 104 105 |
# File 'lib/vagrant/action/general/package.rb', line 102 def create_box_folder(folder_path) @env[:ui].info(I18n.t("vagrant.actions.general.package.box_folder", folder_path: folder_path)) FileUtils.mkdir_p(folder_path) end |
#invalid_info? ⇒ Boolean
Check to see if package.info is a valid file and titled info.json
238 239 240 241 242 243 244 |
# File 'lib/vagrant/action/general/package.rb', line 238 def invalid_info? if @env["package.info"] != "" info_path = Pathname.new(@env["package.info"]) return !info_path.file? || File.basename(info_path) != "info.json" end end |
#package_with_folder_path ⇒ Object
97 98 99 100 |
# File 'lib/vagrant/action/general/package.rb', line 97 def package_with_folder_path folder_path = File.("..", @fullpath) create_box_folder(folder_path) unless File.directory?(folder_path) end |
#recover(env) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/vagrant/action/general/package.rb', line 107 def recover(env) @env = env # There are certain exceptions that we don't delete the file for. ignore_exc = [Errors::PackageOutputDirectory, Errors::PackageOutputExists] ignore_exc.each do |exc| return if env["vagrant.error"].is_a?(exc) end # Cleanup any packaged files if the packaging failed at some point. File.delete(fullpath) if File.exist?(fullpath) end |
#setup_private_key ⇒ Object
This will copy the generated private key into the box and use it for SSH by default. We have to do this because we now generate random keypairs on boot, so packaged boxes would stop working without this.
193 194 195 196 197 198 199 200 201 202 203 204 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 |
# File 'lib/vagrant/action/general/package.rb', line 193 def setup_private_key # If we don't have machine, we do nothing (weird) return if !@env[:machine] # If we don't have a data dir, we also do nothing (base package) return if !@env[:machine].data_dir # If we don't have a generated private key, we do nothing path = @env[:machine].data_dir.join("private_key") if !path.file? # If we have a private key that was copied into this box, # then we copy that. This is a bit of a heuristic and can be a # security risk if the key is named the correct thing, but # we'll take that risk for dev environments. (@env[:machine].config.ssh.private_key_path || []).each do |p| # If we have the correctly named key, copy it if File.basename(p) == "vagrant_private_key" path = Pathname.new(p) break end end end # If we still have no matching key, do nothing return if !path.file? # Copy it into our box directory dir = Pathname.new(@env["package.directory"]) new_path = dir.join("vagrant_private_key") FileUtils.cp(path, new_path) # Append it to the Vagrantfile (or create a Vagrantfile) vf_path = dir.join("Vagrantfile") mode = "w+" mode = "a" if vf_path.file? vf_path.open(mode) do |f| f.binmode f.puts f.puts %Q[Vagrant.configure("2") do |config|] f.puts %Q[ config.ssh.private_key_path = File.expand_path("../vagrant_private_key", __FILE__)] f.puts %Q[end] end end |
#write_metadata_json ⇒ Object
Write the metadata file into the box so that the provider can be automatically detected when adding the box
175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/vagrant/action/general/package.rb', line 175 def = File.join(@env["package.directory"], "metadata.json") return if File.exist?() if @env[:machine] && @env[:machine].provider_name provider_name = @env[:machine].provider_name elsif @env[:env] && @env[:env].default_provider provider_name = @env[:env].default_provider else return end File.write(, {provider: provider_name}.to_json) end |