Merge pull request #35 from fgrehm/0.3.0

0.3.0
This commit is contained in:
Fabio Rehm 2013-08-05 09:16:08 -07:00
commit 41ae83f407
18 changed files with 217 additions and 90 deletions

View file

@ -1,4 +1,12 @@
## [0.3.0](https://github.com/fgrehm/vagrant-cachier/compare/v0.2.0...master) (unreleased) ## [0.3.0](https://github.com/fgrehm/vagrant-cachier/compare/v0.2.0...v0.3.0) (Aug 5, 2013)
BACKWARDS INCOMPATIBILITIES:
- Machine scoped cache dirs are now kept on `.vagrant/machines/MACHINE/cache`
to allow downloaded packages to be reused between providers. If a single cache
directory exists, the plugin will automatically move it to the right place,
if multiple directories are found, it will halt execution and will error out,
letting the user know what has to be done in order to fix things.
FEATURES: FEATURES:

View file

@ -25,7 +25,7 @@ GIT
PATH PATH
remote: . remote: .
specs: specs:
vagrant-cachier (0.3.0.dev) vagrant-cachier (0.3.0)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/

View file

@ -36,10 +36,8 @@ For more information about available buckets, please see the [configuration sect
* Vagrant's built in VirtualBox provider * Vagrant's built in VirtualBox provider
* [vagrant-lxc](https://github.com/fgrehm/vagrant-lxc) * [vagrant-lxc](https://github.com/fgrehm/vagrant-lxc)
* [VMware providers](http://www.vagrantup.com/vmware) with NFS enabled (See
_It is possibly compatible with the [VMware providers](http://www.vagrantup.com/vmware) [GH-24](https://github.com/fgrehm/vagrant-cachier/issues/24) for more info)
as well but I haven't tried yet._
## How does it work? ## How does it work?

View file

@ -11,7 +11,7 @@ module VagrantPlugins
@env = env @env = env
if env[:machine].state.id == :running && symlinks.any? if env[:machine].state.id == :running && symlinks.any?
env[:ui].info 'Removing cache buckets symlinks...' env[:ui].info I18n.t('vagrant_cachier.cleanup')
symlinks.each do |symlink| symlinks.each do |symlink|
remove_symlink symlink remove_symlink symlink
end end
@ -37,4 +37,3 @@ module VagrantPlugins
end end
end end
end end

View file

@ -0,0 +1,63 @@
require_relative '../errors'
module VagrantPlugins
module Cachier
class Action
class EnsureSingleCacheRoot
def initialize(app, env)
@app = app
end
def call(env)
@env = env
# If the cache is scoped to boxes or the existing cache dirs are not
# provider specific, there's nothing we need to do
if cache_scoped_to_machine? && provider_specific_cache_dirs.any?
ensure_single_cache_root_exists!
end
@app.call(env)
end
def cache_scoped_to_machine?
@env[:machine].config.cache.scope.to_sym == :machine
end
def ensure_single_cache_root_exists!
if provider_specific_cache_dirs.size > 1
cache_dirs = provider_specific_cache_dirs.map do |dir|
" - #{dir.to_s.gsub(/^#{@env[:root_path]}\//, '')}"
end
machine_path = @env[:machine].data_dir.parent.to_s.gsub(/^#{@env[:root_path]}\//, '')
raise Cachier::Errors::MultipleProviderSpecificCacheDirsFound,
machine: @env[:machine].name,
machine_path: machine_path,
dirs: cache_dirs.join("\n")
else
current_path = provider_specific_cache_dirs.first.to_s.gsub(/^#{@env[:root_path]}\//, '')
new_path = @env[:machine].data_dir.parent.join('cache')
FileUtils.rm_rf new_path.to_s if new_path.directory?
new_path = new_path.to_s.gsub(/^#{@env[:root_path]}\//, '')
# If we got here there is a single provider specific cacher dir, so
# let's be nice with users and just fix it ;)
@env[:ui].warn I18n.t('vagrant_cachier.will_fix_machine_cache_dir',
current_path: current_path,
new_path: new_path)
FileUtils.mv current_path, new_path
end
end
def provider_specific_cache_dirs
return @provider_specific_cache_dirs if @provider_specific_cache_dirs
# By default data_dir points to ./.vagrant/machines/<NAME>/<PROVIDER>,
# so we go one directory up
machine_dir = @env[:machine].data_dir.parent
@provider_specific_cache_dirs = Pathname.glob(machine_dir.join('*/cache'))
end
end
end
end
end

View file

@ -1,70 +0,0 @@
require_relative '../bucket'
module VagrantPlugins
module Cachier
module Action
module ProvisionExt
def self.included(base)
base.class_eval do
def cachier_debug(msg)
@logger.debug "[CACHIER] #{msg}"
end
alias :old_call :call
def call(env)
return old_call(env) unless env[:machine].config.cache.enabled?
@env = env
FileUtils.mkdir_p(cache_root.to_s) unless cache_root.exist?
nfs_flag = env[:machine].config.cache.enable_nfs
env[:machine].config.vm.synced_folder cache_root, '/tmp/vagrant-cache', id: "vagrant-cache", nfs: nfs_flag
env[:cache_dirs] = []
old_call(env)
configure_cache_buckets
end
alias :old_run_provisioner :run_provisioner
def run_provisioner(*args)
configure_cache_buckets
old_run_provisioner(*args)
end
def configure_cache_buckets
if @env[:machine].config.cache.auto_detect
Bucket.auto_detect(@env)
end
return unless @env[:machine].config.cache.buckets.any?
@env[:ui].info 'Configuring cache buckets...'
cache_config = @env[:machine].config.cache
cache_config.buckets.each do |bucket_name, configs|
cachier_debug "Installing #{bucket_name} with configs #{configs.inspect}"
Bucket.install(bucket_name, @env, configs)
end
data_file = @env[:machine].data_dir.join('cache_dirs')
data_file.open('w') { |f| f.print @env[:cache_dirs].uniq.join("\n") }
end
def cache_root
@cache_root ||= case @env[:machine].config.cache.scope
when :box
@env[:home_path].join('cache', @env[:machine].box.name)
when :machine
@env[:machine].data_dir.join('cache')
else
raise "Unknown cache scope: '#{@env[:machine].config.cache.scope}'"
end
end
end
end
end
end
end
end

View file

@ -24,7 +24,7 @@ module VagrantPlugins
end end
end end
else else
@env[:ui].info "Skipping APT cache bucket as the guest machine does not support it" @env[:ui].info I18n.t('vagrant_cachier.skipping_bucket', bucket: 'APT')
end end
end end
end end

View file

@ -24,7 +24,7 @@ module VagrantPlugins
end end
end end
else else
@env[:ui].info "Skipping Chef cache bucket as the guest machine does not support it" @env[:ui].info I18n.t('vagrant_cachier.skipping_bucket', bucket: 'Chef')
end end
end end
end end

View file

@ -29,7 +29,7 @@ module VagrantPlugins
end end
end end
else else
@env[:ui].info "Skipping RubyGems cache bucket as the guest machine does not support it" @env[:ui].info I18n.t('vagrant_cachier.skipping_bucket', bucket: 'RubyGems')
end end
end end
end end

View file

@ -24,7 +24,7 @@ module VagrantPlugins
end end
end end
else else
@env[:ui].info "Skipping Pacman cache bucket as the guest machine does not support it" @env[:ui].info I18n.t('vagrant_cachier.skipping_bucket', bucket: 'Pacman')
end end
end end
end end

View file

@ -29,7 +29,7 @@ module VagrantPlugins
end end
end end
else else
@env[:ui].info "Skipping RVM cache bucket as the guest machine does not support it" @env[:ui].info I18n.t('vagrant_cachier.skipping_bucket', bucket: 'RVM')
end end
end end
end end

View file

@ -27,7 +27,7 @@ module VagrantPlugins
end end
end end
else else
@env[:ui].info "Skipping Yum cache bucket as the guest machine does not support it" @env[:ui].info I18n.t('vagrant_cachier.skipping_bucket', bucket: 'Yum')
end end
end end
end end

View file

@ -4,6 +4,8 @@ module VagrantPlugins
attr_accessor :scope, :auto_detect, :enable_nfs attr_accessor :scope, :auto_detect, :enable_nfs
attr_reader :buckets attr_reader :buckets
ALLOWED_SCOPES = %w( box machine )
def initialize def initialize
@scope = UNSET_VALUE @scope = UNSET_VALUE
@auto_detect = UNSET_VALUE @auto_detect = UNSET_VALUE
@ -14,6 +16,18 @@ module VagrantPlugins
(@buckets ||= {})[bucket] = opts (@buckets ||= {})[bucket] = opts
end end
def validate(machine)
errors = _detected_errors
if enabled? && ! ALLOWED_SCOPES.include?(@scope.to_s)
errors << I18n.t('vagrant_cachier.unknown_cache_scope',
allowed: ALLOWED_SCOPES.inspect,
cache_scope: @scope)
end
{ "vagrant cachier" => errors }
end
def finalize! def finalize!
return unless enabled? return unless enabled?

View file

@ -0,0 +1,9 @@
module VagrantPlugins
module Cachier
module Errors
class MultipleProviderSpecificCacheDirsFound < Vagrant::Errors::VagrantError
error_key(:multiple_provider_specific_cache_dirs_found)
end
end
end
end

View file

@ -1,8 +1,11 @@
require_relative 'action/provision_ext' require_relative 'provision_ext'
Vagrant::Action::Builtin::Provision.class_eval do Vagrant::Action::Builtin::Provision.class_eval do
include VagrantPlugins::Cachier::Action::ProvisionExt include VagrantPlugins::Cachier::ProvisionExt
end end
# Add our custom translations to the load path
I18n.load_path << File.expand_path("../../../locales/en.yml", __FILE__)
module VagrantPlugins module VagrantPlugins
module Cachier module Cachier
class Plugin < Vagrant.plugin('2') class Plugin < Vagrant.plugin('2')
@ -43,12 +46,27 @@ module VagrantPlugins
Cap::Arch::PacmanCacheDir Cap::Arch::PacmanCacheDir
end end
# TODO: This should be generic, we don't want to hard code every single
# possible provider action class that Vagrant might have
ensure_single_cache_root = lambda do |hook|
require_relative 'action/ensure_single_cache_root'
hook.before VagrantPlugins::ProviderVirtualBox::Action::Boot, Action::EnsureSingleCacheRoot
if defined?(Vagrant::LXC)
# TODO: Require just the boot action file once its "require dependencies" are sorted out
require 'vagrant-lxc/action'
hook.before Vagrant::LXC::Action::Boot, Action::EnsureSingleCacheRoot
end
end
action_hook 'ensure-single-cache-root-exists-on-up', :machine_action_up, &ensure_single_cache_root
action_hook 'ensure-single-cache-root-exists-on-reload', :machine_action_reload, &ensure_single_cache_root
clean_action_hook = lambda do |hook| clean_action_hook = lambda do |hook|
require_relative 'action/clean' require_relative 'action/clean'
hook.before Vagrant::Action::Builtin::GracefulHalt, VagrantPlugins::Cachier::Action::Clean hook.before Vagrant::Action::Builtin::GracefulHalt, Action::Clean
end end
action_hook 'remove-guest-symlinks-on-machine-halt', :machine_action_halt, &clean_action_hook action_hook 'remove-guest-symlinks-on-halt', :machine_action_halt, &clean_action_hook
action_hook 'remove-guest-symlinks-on-machine-package', :machine_action_package, &clean_action_hook action_hook 'remove-guest-symlinks-on-package', :machine_action_package, &clean_action_hook
end end
end end
end end

View file

@ -0,0 +1,68 @@
require_relative 'bucket'
module VagrantPlugins
module Cachier
module ProvisionExt
def self.included(base)
base.class_eval do
def cachier_debug(msg)
@logger.debug "[CACHIER] #{msg}"
end
alias :old_call :call
def call(env)
return old_call(env) unless env[:machine].config.cache.enabled?
@env = env
FileUtils.mkdir_p(cache_root.to_s) unless cache_root.exist?
nfs_flag = env[:machine].config.cache.enable_nfs
env[:machine].config.vm.synced_folder cache_root, '/tmp/vagrant-cache', id: "vagrant-cache", nfs: nfs_flag
env[:cache_dirs] = []
old_call(env)
configure_cache_buckets
end
alias :old_run_provisioner :run_provisioner
def run_provisioner(*args)
configure_cache_buckets
old_run_provisioner(*args)
end
def configure_cache_buckets
if @env[:machine].config.cache.auto_detect
Bucket.auto_detect(@env)
end
return unless @env[:machine].config.cache.buckets.any?
@env[:ui].info 'Configuring cache buckets...'
cache_config = @env[:machine].config.cache
cache_config.buckets.each do |bucket_name, configs|
cachier_debug "Installing #{bucket_name} with configs #{configs.inspect}"
Bucket.install(bucket_name, @env, configs)
end
data_file = @env[:machine].data_dir.join('cache_dirs')
data_file.open('w') { |f| f.print @env[:cache_dirs].uniq.join("\n") }
end
def cache_root
@cache_root ||= case @env[:machine].config.cache.scope.to_sym
when :box
@env[:home_path].join('cache', @env[:machine].box.name)
when :machine
@env[:machine].data_dir.parent.join('cache')
else
raise "Unknown cache scope: '#{@env[:machine].config.cache.scope}'"
end
end
end
end
end
end
end

View file

@ -1,5 +1,5 @@
module VagrantPlugins module VagrantPlugins
module Cachier module Cachier
VERSION = "0.3.0.dev" VERSION = "0.3.0"
end end
end end

20
locales/en.yml Normal file
View file

@ -0,0 +1,20 @@
en:
vagrant_cachier:
cleanup: |-
Removing cache buckets symlinks...
skipping_bucket: |-
Skipping %{bucket} cache bucket as the guest machine does not support it
unknown_cache_scope: |-
Unknown cache scope '%{cache_scope}' (allowed scopes: %{allowed})
will_fix_machine_cache_dir: |-
A vagrant-cachier provider specific cache dir was found under
'%{current_path}' and it will be moved to
'%{new_path}' as it is the new path for keeping machine
scoped cache dirs starting with the 0.3.0 version of the plugin.
vagrant:
errors:
multiple_provider_specific_cache_dirs_found: |-
There are multiple provider specific cache dirs for the '%{machine}' machine:
%{dirs}
Please move one of them up to `%{machine_path}/cache` and remove the others
before bringing the machine up again.