Class: Vagrant::Action::General::Package

Inherits:
Object
  • Object
show all
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.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 Method Summary collapse

Constructor Details

#initialize(app, env) ⇒ Package



23
24
25
26
27
28
# File 'lib/vagrant/action/general/package.rb', line 23

def initialize(app, env)
  @app = app

  env["package.files"]  ||= {}
  env["package.output"] ||= "package.box"
end

Instance Method Details

#call(env) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/vagrant/action/general/package.rb', line 30

def call(env)
  @env = env

  raise Errors::PackageOutputDirectory if File.directory?(tar_path)
  raise Errors::PackageOutputExists if File.exist?(tar_path)
  raise Errors::PackageRequiresDirectory if !env["package.directory"] ||
    !File.directory?(env["package.directory"])

  @app.call(env)

  @env[:ui].info I18n.t("vagrant.actions.general.package.compressing", tar_path: tar_path)
  copy_include_files
  setup_private_key
  compress
end

#compressObject

Compress the exported file into a package



87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/vagrant/action/general/package.rb', line 87

def compress
  # Get the output path. We have to do this up here so that the
  # pwd returns the proper thing.
  output_path = tar_path.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_filesObject

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



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/vagrant/action/general/package.rb', line 62

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 direcotry 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

#recover(env) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/vagrant/action/general/package.rb', line 46

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(tar_path) if File.exist?(tar_path)
end

#setup_private_keyObject

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.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/vagrant/action/general/package.rb', line 106

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")
  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

#tar_pathObject

Path to the final box output file



136
137
138
# File 'lib/vagrant/action/general/package.rb', line 136

def tar_path
  File.expand_path(@env["package.output"], FileUtils.pwd)
end