Index: upgrade/upgrade.go |
=== added file 'upgrade/upgrade.go' |
--- upgrade/upgrade.go 1970-01-01 00:00:00 +0000 |
+++ upgrade/upgrade.go 2012-06-11 17:52:25 +0000 |
@@ -0,0 +1,89 @@ |
+package upgrade |
+ |
+import ( |
+ "errors" |
+ "fmt" |
+ "launchpad.net/gnuflag" |
+ "os" |
+ "sync" |
+) |
+ |
+var upgradedFlag = gnuflag.Bool("upgraded", false, "process is started by the upgrader process") |
+ |
+var ( |
+ mutex sync.Mutex |
+ started bool |
+ startError error |
+) |
+ |
+// Start signals to the upgrader that the command has started. If it |
+// returns with an error, the command should abort and exit; otherwise |
+// it should assume normal operation. |
+func Start() error { |
+ if !*upgradedFlag { |
+ return nil |
+ } |
+ mutex.Lock() |
+ defer mutex.Unlock() |
+ if !started { |
+ WriteMsg(os.Stdout, "started") |
+ _, startError = ReadMsg(os.Stdin, "run") |
+ started = true |
+ } |
+ return startError |
+} |
+ |
+// StartError signals to the upgrader that the command |
+// has failed to start correctly. The caller should arrange |
+// to exit the program after calling this function. |
+// Any subsequent calls to Start will fail with the given |
+// error. |
+func StartError(err error) { |
+ if !*upgradedFlag { |
+ return |
+ } |
+ mutex.Lock() |
+ defer mutex.Unlock() |
+ if !started { |
+ WriteMsg(os.Stdout, "error", err.Error()) |
+ startError = err |
+ started = true |
+ } |
+} |
+ |
+// Upgrade requests to the upgrader that the current command be upgraded |
+// by running the given executable command. If the command succeeds in |
+// starting, the shutdown function will be called to shut down all |
+// operations. If it succeeds, Upgrade will return no error, and the |
+// caller should exit the program to allow the new command to take over |
+// operations. |
+func Upgrade(shutdown func() error, cmd string, args ...string) error { |
+ if !*upgradedFlag { |
+ return errors.New("cannot upgrade when not started from the upgrader") |
+ } |
+ mutex.Lock() |
+ defer mutex.Unlock() |
+ if !started { |
+ return errors.New("upgrade called before start") |
+ } |
+ if startError != nil { |
+ return fmt.Errorf("start encountered an error so cannot upgrade: %v", startError) |
+ } |
+ m := make([]string, 2+len(args)) |
+ m[0] = "upgrade" |
+ m[1] = cmd |
+ copy(m[2:], args) |
+ WriteMsg(os.Stdout, m...) |
+ _, err := ReadMsg(os.Stdin, "upgraded") |
+ if err != nil { |
+ return err |
+ } |
+ err = shutdown() |
+ if err != nil { |
+ WriteMsg(os.Stdout, "error", err.Error()) |
+ return fmt.Errorf("shutdown failed: %v", err) |
+ } |
+ WriteMsg(os.Stdout, "shutdown") |
+ // TODO os.Exit(0) ? |
+ return nil |
+} |