github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/packer/hook.go (about) 1 package packer 2 3 import ( 4 "sync" 5 ) 6 7 // This is the hook that should be fired for provisioners to run. 8 const HookProvision = "packer_provision" 9 10 // A Hook is used to hook into an arbitrarily named location in a build, 11 // allowing custom behavior to run at certain points along a build. 12 // 13 // Run is called when the hook is called, with the name of the hook and 14 // arbitrary data associated with it. To know what format the data is in, 15 // you must reference the documentation for the specific hook you're interested 16 // in. In addition to that, the Hook is given access to a UI so that it can 17 // output things to the user. 18 // 19 // Cancel is called when the hook needs to be cancelled. This will usually 20 // be called when Run is still in progress so the mechanism that handles this 21 // must be race-free. Cancel should attempt to cancel the hook in the 22 // quickest, safest way possible. 23 type Hook interface { 24 Run(string, Ui, Communicator, interface{}) error 25 Cancel() 26 } 27 28 // A Hook implementation that dispatches based on an internal mapping. 29 type DispatchHook struct { 30 Mapping map[string][]Hook 31 32 l sync.Mutex 33 cancelled bool 34 runningHook Hook 35 } 36 37 // Runs the hook with the given name by dispatching it to the proper 38 // hooks if a mapping exists. If a mapping doesn't exist, then nothing 39 // happens. 40 func (h *DispatchHook) Run(name string, ui Ui, comm Communicator, data interface{}) error { 41 h.l.Lock() 42 h.cancelled = false 43 h.l.Unlock() 44 45 // Make sure when we exit that we reset the running hook. 46 defer func() { 47 h.l.Lock() 48 defer h.l.Unlock() 49 h.runningHook = nil 50 }() 51 52 hooks, ok := h.Mapping[name] 53 if !ok { 54 // No hooks for that name. No problem. 55 return nil 56 } 57 58 for _, hook := range hooks { 59 h.l.Lock() 60 if h.cancelled { 61 h.l.Unlock() 62 return nil 63 } 64 65 h.runningHook = hook 66 h.l.Unlock() 67 68 if err := hook.Run(name, ui, comm, data); err != nil { 69 return err 70 } 71 } 72 73 return nil 74 } 75 76 // Cancels all the hooks that are currently in-flight, if any. This will 77 // block until the hooks are all cancelled. 78 func (h *DispatchHook) Cancel() { 79 h.l.Lock() 80 defer h.l.Unlock() 81 82 if h.runningHook != nil { 83 h.runningHook.Cancel() 84 } 85 86 h.cancelled = true 87 }