File: trigger.rb

package info (click to toggle)
vagrant 2.2.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 8,072 kB
  • sloc: ruby: 80,731; sh: 369; makefile: 9; lisp: 1
file content (201 lines) | stat: -rw-r--r-- 6,458 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
require "vagrant"
require File.expand_path("../vm_trigger", __FILE__)

module VagrantPlugins
  module Kernel_V2
    class TriggerConfig < Vagrant.plugin("2", :config)
      # The TriggerConfig class is what gets called when a user
      # defines a new trigger in their Vagrantfile. The two entry points are
      # either `config.trigger.before` or `config.trigger.after`.

      def initialize
        @logger = Log4r::Logger.new("vagrant::config::trigger")

        # Internal State
        @_before_triggers = [] # An array of VagrantConfigTrigger objects
        @_after_triggers  = [] # An array of VagrantConfigTrigger objects
      end

      #-------------------------------------------------------------------
      # Trigger before/after functions
      #-------------------------------------------------------------------
      #
      # Commands are expected to be ether:
      #   - splat
      #     + config.trigger.before :up, :destroy, :halt do |trigger|....
      #   - array
      #     + config.trigger.before [:up, :destroy, :halt] do |trigger|....
      #
      # Config is expected to be given as a block, or the last parameter as a hash
      #
      #   - block
      #     + config.trigger.before :up, :destroy, :halt do |trigger|
      #         trigger.option = "option"
      #       end
      #   - hash
      #     + config.trigger.before :up, :destroy, :halt, options: "option"

      # Reads in and parses Vagrant command whitelist and settings for a defined
      # trigger
      #
      # @param [Symbol] command Vagrant command to create trigger on
      # @param [Block] block The defined before block
      def before(*command, &block)
        command.flatten!
        blk = block

        if !block_given? && command.last.is_a?(Hash)
          # We were given a hash rather than a block,
          # so the last element should be the "config block"
          # and the rest are commands for the trigger
          blk = command.pop
        elsif !block_given?
          raise Vagrant::Errors::TriggersNoBlockGiven,
            command: command
        end

        command.each do |cmd|
          trigger = create_trigger(cmd, blk)
          @_before_triggers << trigger
        end
      end

      # Reads in and parses Vagrant command whitelist and settings for a defined
      # trigger
      #
      # @param [Symbol] command Vagrant command to create trigger on
      # @param [Block] block The defined after block
      def after(*command, &block)
        command.flatten!
        blk = block

        if !block_given? && command.last.is_a?(Hash)
          # We were given a hash rather than a block,
          # so the last element should be the "config block"
          # and the rest are commands for the trigger
          blk = command.pop
        elsif !block_given?
          raise Vagrant::Errors::TriggersNoBlockGiven,
            command: command
        end

        command.each do |cmd|
          trigger = create_trigger(cmd, blk)
          @_after_triggers << trigger
        end
      end

      #-------------------------------------------------------------------
      # Internal methods, don't call these.
      #-------------------------------------------------------------------

      # Creates a new trigger config. If a block is given, parse that block
      # by calling it with the created trigger. Otherwise set the options if it's
      # a hash.
      #
      # @param [Symbol] command Vagrant command to create trigger on
      # @param [Block] block The defined config block
      # @return [VagrantConfigTrigger]
      def create_trigger(command, block)
        trigger = VagrantConfigTrigger.new(command)
        if block.is_a?(Hash)
          trigger.set_options(block)
        else
          block.call(trigger, VagrantConfigTrigger)
        end
        return trigger
      end

      def merge(other)
        super.tap do |result|
          new_before_triggers = []
          new_after_triggers = []
          other_defined_before_triggers = other.instance_variable_get(:@_before_triggers)
          other_defined_after_triggers = other.instance_variable_get(:@_after_triggers)

          @_before_triggers.each do |bt|
            other_bft = other_defined_before_triggers.find { |o| bt.id == o.id }
            if other_bft
              # Override, take it
              other_bft = bt.merge(other_bft)

              # Preserve order, always
              bt = other_bft
              other_defined_before_triggers.delete(other_bft)
            end

            new_before_triggers << bt.dup
          end

          other_defined_before_triggers.each do |obt|
            new_before_triggers << obt.dup
          end
          result.instance_variable_set(:@_before_triggers, new_before_triggers)

          @_after_triggers.each do |at|
            other_aft = other_defined_after_triggers.find { |o| at.id == o.id }
            if other_aft
              # Override, take it
              other_aft = at.merge(other_aft)

              # Preserve order, always
              at = other_aft
              other_defined_after_triggers.delete(other_aft)
            end

            new_after_triggers << at.dup
          end

          other_defined_after_triggers.each do |oat|
            new_after_triggers << oat.dup
          end
          result.instance_variable_set(:@_after_triggers, new_after_triggers)
        end
      end

      # Iterates over all defined triggers and finalizes their config objects
      def finalize!
        if !@_before_triggers.empty?
          @_before_triggers.map { |t| t.finalize! }
        end

        if !@_after_triggers.empty?
          @_after_triggers.map { |t| t.finalize! }
        end
      end

      # Validate Trigger Arrays
      def validate(machine)
        errors = _detected_errors
        @_before_triggers.each do |bt|
          error = bt.validate(machine)
          errors.concat error if !error.empty?
        end

        @_after_triggers.each do |at|
          error = at.validate(machine)
          errors.concat error if !error.empty?
        end

        {"trigger" => errors}
      end

      # return [Array]
      def before_triggers
        @_before_triggers
      end

      # return [Array]
      def after_triggers
        @_after_triggers
      end

      # The String representation of this Trigger.
      #
      # @return [String]
      def to_s
        "trigger"
      end
    end
  end
end