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:

View file

@ -25,7 +25,7 @@ GIT
PATH
remote: .
specs:
vagrant-cachier (0.3.0.dev)
vagrant-cachier (0.3.0)
GEM
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-lxc](https://github.com/fgrehm/vagrant-lxc)
_It is possibly compatible with the [VMware providers](http://www.vagrantup.com/vmware)
as well but I haven't tried yet._
* [VMware providers](http://www.vagrantup.com/vmware) with NFS enabled (See
[GH-24](https://github.com/fgrehm/vagrant-cachier/issues/24) for more info)
## How does it work?

View file

@ -11,7 +11,7 @@ module VagrantPlugins
@env = env
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|
remove_symlink symlink
end
@ -37,4 +37,3 @@ module VagrantPlugins
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
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

View file

@ -24,7 +24,7 @@ module VagrantPlugins
end
end
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

View file

@ -29,7 +29,7 @@ module VagrantPlugins
end
end
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

View file

@ -24,7 +24,7 @@ module VagrantPlugins
end
end
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

View file

@ -29,7 +29,7 @@ module VagrantPlugins
end
end
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

View file

@ -27,7 +27,7 @@ module VagrantPlugins
end
end
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

View file

@ -4,6 +4,8 @@ module VagrantPlugins
attr_accessor :scope, :auto_detect, :enable_nfs
attr_reader :buckets
ALLOWED_SCOPES = %w( box machine )
def initialize
@scope = UNSET_VALUE
@auto_detect = UNSET_VALUE
@ -14,6 +16,18 @@ module VagrantPlugins
(@buckets ||= {})[bucket] = opts
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!
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
include VagrantPlugins::Cachier::Action::ProvisionExt
include VagrantPlugins::Cachier::ProvisionExt
end
# Add our custom translations to the load path
I18n.load_path << File.expand_path("../../../locales/en.yml", __FILE__)
module VagrantPlugins
module Cachier
class Plugin < Vagrant.plugin('2')
@ -43,12 +46,27 @@ module VagrantPlugins
Cap::Arch::PacmanCacheDir
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|
require_relative 'action/clean'
hook.before Vagrant::Action::Builtin::GracefulHalt, VagrantPlugins::Cachier::Action::Clean
hook.before Vagrant::Action::Builtin::GracefulHalt, Action::Clean
end
action_hook 'remove-guest-symlinks-on-machine-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-halt', :machine_action_halt, &clean_action_hook
action_hook 'remove-guest-symlinks-on-package', :machine_action_package, &clean_action_hook
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 Cachier
VERSION = "0.3.0.dev"
VERSION = "0.3.0"
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.