vagrant-triggers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+
3
+ .bundle
4
+ pkg/*
5
+ Gemfile.lock
6
+
7
+ .rspec
8
+
9
+ .vagrant
10
+ .vagrant.d/*
11
+ Vagrantfile
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
7
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Emiliano Ticci
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,65 @@
1
+ # vagrant-triggers
2
+
3
+ Allow the definition of arbitrary scripts that will run on the host before and/or after Vagrant commands.
4
+
5
+ ## Installation
6
+
7
+ Ensure you have downloaded and installed Vagrant from the
8
+ [Vagrant downloads page](http://downloads.vagrantup.com/).
9
+
10
+ Installation is performed in the prescribed manner for Vagrant 1.1+ plugins.
11
+
12
+ $ vagrant plugin install vagrant-triggers
13
+
14
+ ## Usage
15
+
16
+ ### Basic usage
17
+
18
+ The following ```Vagrantfile``` configuration options are added:
19
+
20
+ ```
21
+ config.trigger.before :command, :execute => "script"
22
+ ```
23
+
24
+ ```
25
+ config.trigger.after :command, :execute => "script"
26
+ ```
27
+
28
+ ### Options
29
+
30
+ * ```:execute => "script"```: the script to execute
31
+ * ```:force => true```: continue even if the script fails (exits with non-zero code)
32
+ * ```:stdout => true```: display script output
33
+
34
+ ## Example
35
+
36
+ In the following example a VirtualBox VM (not managed by Vagrant) will be tied to the machine defined in ```Vagrantfile```, to make so that it follows its lifecycle:
37
+
38
+ ```ruby
39
+
40
+ Vagrant.configure("2") do |config|
41
+
42
+ {
43
+ :halt => "controlvm 22aed8b3-d246-40d5-8ad4-176c17552c43 acpipowerbutton",
44
+ :resume => "startvm 22aed8b3-d246-40d5-8ad4-176c17552c43 --type headless",
45
+ :suspend => "controlvm 22aed8b3-d246-40d5-8ad4-176c17552c43 savestate",
46
+ :up => "startvm 22aed8b3-d246-40d5-8ad4-176c17552c43 --type headless"
47
+ }.each do |command, trigger|
48
+ config.trigger.before command, :execute => "vboxmanage #{trigger}", :stdout => true
49
+ end
50
+
51
+ end
52
+ ```
53
+
54
+ ## Contributing
55
+
56
+ To contribute, clone the repository, and use [Bundler](http://bundler.io/)
57
+ to install dependencies:
58
+
59
+ $ bundle
60
+
61
+ To run the plugin's tests:
62
+
63
+ $ bundle exec rake
64
+
65
+ You can now fork this repository, make your changes and send a pull request.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => "spec"
@@ -0,0 +1,18 @@
1
+ require "pathname"
2
+ require "vagrant-triggers/plugin"
3
+
4
+ module VagrantPlugins
5
+ module Triggers
6
+ lib_path = Pathname.new(File.expand_path("../vagrant-triggers", __FILE__))
7
+ autoload :Action, lib_path.join("action")
8
+ autoload :Config, lib_path.join("config")
9
+ autoload :Errors, lib_path.join("errors")
10
+
11
+ # This returns the path to the source of this plugin.
12
+ #
13
+ # @return [Pathname]
14
+ def self.source_root
15
+ @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ module VagrantPlugins
2
+ module Triggers
3
+ module Action
4
+ def self.action_trigger(condition)
5
+ Vagrant::Action::Builder.new.tap do |b|
6
+ b.use Trigger, condition
7
+ end
8
+ end
9
+
10
+ # Autoload farm
11
+ action_root = Pathname.new(File.expand_path("../action", __FILE__))
12
+ autoload :Trigger, action_root.join("trigger")
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ require "log4r"
2
+ require "shellwords"
3
+ require "vagrant/util/subprocess"
4
+
5
+ module VagrantPlugins
6
+ module Triggers
7
+ module Action
8
+ class Trigger
9
+ def initialize(app, env, condition)
10
+ @app = app
11
+ @condition = condition
12
+ @env = env
13
+ @logger = Log4r::Logger.new("vagrant::plugins::triggers::trigger")
14
+ end
15
+
16
+ def call(env)
17
+ fire_triggers
18
+
19
+ # Carry on
20
+ @app.call(env)
21
+ end
22
+
23
+ def fire_triggers
24
+ # Triggers don't fire on environment load and unload.
25
+ return if [:environment_load, :environment_unload].include?(@env[:action_name])
26
+ current_action = @env[:machine_action]
27
+ # Also don't fire if machine action is not defined.
28
+ return unless current_action
29
+ @logger.debug("Looking for triggers #{@condition} action #{current_action}.")
30
+ triggers_to_fire = @env[:machine].config.trigger.triggers.find_all { |t| t[:action] == current_action && t[:condition] == @condition }
31
+ unless triggers_to_fire.empty?
32
+ @env[:ui].info "Running triggers #{@condition} action..."
33
+ triggers_to_fire.each do |trigger|
34
+ options = trigger[:options]
35
+ if options[:execute]
36
+ raw_command = options[:execute]
37
+ @env[:ui].info 'Executing command "' + raw_command + '"...'
38
+ command = Shellwords.shellsplit(raw_command)
39
+ result = Vagrant::Util::Subprocess.execute(command[0], *command[1..-1])
40
+ if result.exit_code != 0 && !options[:force]
41
+ raise Errors::CommandFailed, :command => raw_command, :stderr => result.stderr
42
+ end
43
+ if options[:stdout]
44
+ @env[:ui].info "Command output:\n\n#{result.stdout}\n"
45
+ end
46
+ else
47
+ @logger.debug("Trigger command not found.")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,29 @@
1
+ module VagrantPlugins
2
+ module Triggers
3
+ class Config < Vagrant.plugin("2", :config)
4
+ attr_reader :triggers
5
+
6
+ def initialize
7
+ @triggers = []
8
+ end
9
+
10
+ def after(action, options = {})
11
+ @triggers << { :action => action, :condition => :after, :options => options }
12
+ end
13
+
14
+ def before(action, options = {})
15
+ @triggers << { :action => action, :condition => :before, :options => options }
16
+ end
17
+
18
+ def validate(machine)
19
+ errors = []
20
+
21
+ if @__invalid_methods && !@__invalid_methods.empty?
22
+ errors << I18n.t("vagrant.config.common.bad_field", :fields => @__invalid_methods.to_a.sort.join(", "))
23
+ end
24
+
25
+ { "triggers" => errors }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module VagrantPlugins
2
+ module Triggers
3
+ module Errors
4
+ class VagrantTriggerError < Vagrant::Errors::VagrantError
5
+ error_namespace("vagrant_triggers.errors")
6
+ end
7
+
8
+ class CommandFailed < VagrantTriggerError
9
+ error_key(:command_failed)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ begin
2
+ require "vagrant"
3
+ rescue LoadError
4
+ raise "The Vagrant Triggers plugin must be run within Vagrant."
5
+ end
6
+
7
+ # This is a sanity check to make sure no one is attempting to install
8
+ # this into an early Vagrant version.
9
+ if Vagrant::VERSION < "1.1.0"
10
+ raise "The Vagrant Triggers plugin is only compatible with Vagrant 1.1+"
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module Triggers
15
+ class Plugin < Vagrant.plugin("2")
16
+ name "Triggers"
17
+ description <<-DESC
18
+ This plugin allow the definition of arbitrary scripts that
19
+ will run on the host before and/or after Vagrant commands.
20
+ DESC
21
+
22
+ action_hook(:init_i18n, :environment_load) { init_i18n }
23
+
24
+ action_hook(:trigger, Plugin::ALL_ACTIONS) do |hook|
25
+ require_relative "action"
26
+ hook.prepend(Action.action_trigger(:before))
27
+ hook.append(Action.action_trigger(:after))
28
+ end
29
+
30
+ config(:trigger) do
31
+ require_relative "config"
32
+ Config
33
+ end
34
+
35
+ # This initializes the I18n load path so that the plugin specific
36
+ # transations work.
37
+ def self.init_i18n
38
+ I18n.load_path << File.expand_path("locales/en.yml", Triggers.source_root)
39
+ I18n.reload!
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module Triggers
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ en:
2
+ vagrant_triggers:
3
+ errors:
4
+ command_failed: |-
5
+ The command "%{command}" returned a failed exit code. The
6
+ error output is shown below:
7
+
8
+ %{stderr}
@@ -0,0 +1 @@
1
+ require_relative "../lib/vagrant-triggers"
@@ -0,0 +1,78 @@
1
+ require "spec_helper"
2
+ require "vagrant/util/subprocess"
3
+
4
+ describe VagrantPlugins::Triggers::Action::Trigger do
5
+ let(:app) { lambda { |env| } }
6
+ let(:env) { { :action_name => action_name, :machine => machine, :machine_action => machine_action, :ui => ui } }
7
+ let(:condition) { double("condition") }
8
+ let(:action_name) { double("action_name") }
9
+ let(:machine) { double("machine") }
10
+ let(:machine_action) { double("machine_action") }
11
+
12
+ let(:ui) { double("ui", :info => info) }
13
+ let(:info) { double("info") }
14
+
15
+ let(:result) { double("result", :exit_code => 0, :stderr => stderr) }
16
+ let(:stderr) { double("stderr") }
17
+
18
+ before do
19
+ @triggers = [ { :action => machine_action, :condition => condition, :options => { :execute => "foo" } } ]
20
+ machine.stub_chain(:config, :trigger, :triggers).and_return(@triggers)
21
+ Vagrant::Util::Subprocess.stub(:execute => result)
22
+ end
23
+
24
+ it "should skip :environment_load and :environment_unload actions" do
25
+ [:environment_load, :environment_unload].each do |action|
26
+ env.stub(:[]).with(:action_name).and_return(action)
27
+ env.should_not_receive(:[]).with(:machine_action)
28
+ described_class.new(app, env, condition).call(env)
29
+ end
30
+ end
31
+
32
+ it "shouldn't fire if machine action is not defined" do
33
+ env.stub(:[]).with(:action_name)
34
+ env.stub(:[]).with(:machine_action).and_return(nil)
35
+ env.should_not_receive(:[]).with(:machine)
36
+ described_class.new(app, env, condition).call(env)
37
+ end
38
+
39
+ it "should fire trigger when all conditions are satisfied" do
40
+ Vagrant::Util::Subprocess.should_receive(:execute).with("foo")
41
+ described_class.new(app, env, condition).call(env)
42
+ end
43
+
44
+ it "should fire all defined triggers" do
45
+ @triggers << { :action => machine_action, :condition => condition, :options => { :execute => "bar" } }
46
+ Vagrant::Util::Subprocess.should_receive(:execute).twice
47
+ described_class.new(app, env, condition).call(env)
48
+ end
49
+
50
+ it "shouldn't execute trigger with no command" do
51
+ @triggers[0][:options] = {}
52
+ Vagrant::Util::Subprocess.should_not_receive(:execute)
53
+ described_class.new(app, env, condition).call(env)
54
+ end
55
+
56
+ it "shouldn't fire trigger when condition doesn't match" do
57
+ @triggers[0][:condition] = "blah"
58
+ Vagrant::Util::Subprocess.should_not_receive(:execute)
59
+ described_class.new(app, env, condition).call(env)
60
+ end
61
+
62
+ it "shouldn't fire trigger when action doesn't match" do
63
+ @triggers[0][:action] = "blah"
64
+ Vagrant::Util::Subprocess.should_not_receive(:execute)
65
+ described_class.new(app, env, condition).call(env)
66
+ end
67
+
68
+ it "should raise an error if executed command exits with non-zero code" do
69
+ result.stub(:exit_code => 1)
70
+ expect { described_class.new(app, env, condition).call(env) }.to raise_error(VagrantPlugins::Triggers::Errors::CommandFailed)
71
+ end
72
+
73
+ it "shouldn't raise an error if executed command exits with non-zero code but :force option was specified" do
74
+ @triggers[0][:options][:force] = true
75
+ result.stub(:exit_code => 1)
76
+ expect { described_class.new(app, env, condition).call(env) }.to_not raise_error()
77
+ end
78
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ describe VagrantPlugins::Triggers::Config do
4
+ let(:config) { described_class.new }
5
+ let(:machine) { double("machine") }
6
+
7
+ describe "defaults" do
8
+ subject do
9
+ config.tap do |o|
10
+ o.finalize!
11
+ end
12
+ end
13
+
14
+ its("triggers") { should eq [] }
15
+ end
16
+
17
+ describe "accept multiple entries" do
18
+ it "should record multiple entries" do
19
+ config.before :up, :exec => "echo ls"
20
+ config.after :up, :exec => "echo ls"
21
+ expect(config.triggers).to have(2).items
22
+ end
23
+ end
24
+
25
+ describe "validation" do
26
+ it "should validate" do
27
+ config.finalize!
28
+ expect(config.validate(machine)["triggers"]).to have(:no).items
29
+ end
30
+
31
+ it "shouldn't accept invalid methods" do
32
+ config.foo "bar"
33
+ expect(config.validate(machine)["triggers"]).to have(1).item
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ $:.unshift File.expand_path("../lib", __FILE__)
2
+ require "vagrant-triggers/version"
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "vagrant-triggers"
6
+ spec.version = VagrantPlugins::Triggers::VERSION
7
+ spec.authors = "Emiliano Ticci"
8
+ spec.email = "emiticci@gmail.com"
9
+ spec.summary = "Triggers for Vagrant commands."
10
+ spec.description = "This plugin allow the definition of arbitrary scripts that will run on the host before and/or after Vagrant commands."
11
+
12
+ # The following block of code determines the files that should be included
13
+ # in the gem. It does this by reading all the files in the directory where
14
+ # this gemspec is, and parsing out the ignored files from the gitignore.
15
+ # Note that the entire gitignore(5) syntax is not supported, specifically
16
+ # the "!" syntax, but it should mostly work correctly.
17
+ root_path = File.dirname(__FILE__)
18
+ all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
19
+ all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
20
+ gitignore_path = File.join(root_path, ".gitignore")
21
+ gitignore = File.readlines(gitignore_path)
22
+ gitignore.map! { |line| line.chomp.strip }
23
+ gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
24
+
25
+ unignored_files = all_files.reject do |file|
26
+ # Ignore any directories, the gemspec only cares about files
27
+ next true if File.directory?(file)
28
+
29
+ # Ignore any paths that match anything in the gitignore. We do
30
+ # two tests here:
31
+ #
32
+ # - First, test to see if the entire path matches the gitignore.
33
+ # - Second, match if the basename does, this makes it so that things
34
+ # like '.DS_Store' will match sub-directories too (same behavior
35
+ # as git).
36
+ #
37
+ gitignore.any? do |ignore|
38
+ File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
39
+ File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
40
+ end
41
+ end
42
+
43
+ spec.files = unignored_files
44
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
45
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
46
+ spec.require_path = "lib"
47
+
48
+ spec.add_development_dependency "bundler", "~> 1.3"
49
+ spec.add_development_dependency "rake"
50
+ spec.add_development_dependency "rspec"
51
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vagrant-triggers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Emiliano Ticci
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: This plugin allow the definition of arbitrary scripts that will run on
63
+ the host before and/or after Vagrant commands.
64
+ email: emiticci@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - Gemfile
70
+ - lib/vagrant-triggers/action/trigger.rb
71
+ - lib/vagrant-triggers/action.rb
72
+ - lib/vagrant-triggers/config.rb
73
+ - lib/vagrant-triggers/errors.rb
74
+ - lib/vagrant-triggers/plugin.rb
75
+ - lib/vagrant-triggers/version.rb
76
+ - lib/vagrant-triggers.rb
77
+ - LICENSE.txt
78
+ - locales/en.yml
79
+ - Rakefile
80
+ - README.md
81
+ - spec/spec_helper.rb
82
+ - spec/vagrant-triggers/action/trigger_spec.rb
83
+ - spec/vagrant-triggers/config_spec.rb
84
+ - vagrant-triggers.gemspec
85
+ - .gitignore
86
+ homepage:
87
+ licenses: []
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ segments:
99
+ - 0
100
+ hash: -3600971872626738108
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ segments:
108
+ - 0
109
+ hash: -3600971872626738108
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 1.8.23
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: Triggers for Vagrant commands.
116
+ test_files:
117
+ - spec/spec_helper.rb
118
+ - spec/vagrant-triggers/action/trigger_spec.rb
119
+ - spec/vagrant-triggers/config_spec.rb