Skip to content

Instantly share code, notes, and snippets.

@fenollp
Created January 23, 2018 15:48
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fenollp/7e31e6462b10c96aef443351bce6aea7 to your computer and use it in GitHub Desktop.
Save fenollp/7e31e6462b10c96aef443351bce6aea7 to your computer and use it in GitHub Desktop.
How to self-upgrade/swap a running binary in Golang

How to self-upgrade/swap a running binary in Golang

You are writing a CLI client in Go and your users would love to be able to update this client seamlessly.

I'm talking replacing a currently running executable on UNIX platforms.

Using exec

// exa.go
package main

import (
	"os"
	"path"
	"syscall"
)

func main() {
	binary := "./replace.sh"
	args := []string{path.Base(binary)}
	env := os.Environ()

	if err := syscall.Exec(binary, args, env); err != nil {
		panic(err)
	}
}

Just using move

// exa.go
package main
import "os"
import "io/ioutil"

func main() {
	src, dst := "./replace.sh", "./exa_"
	data, err := ioutil.ReadFile(src)
	if err != nil {
		panic(err)
	}
	if err := ioutil.WriteFile(dst, data, 0744); err != nil {
		panic(err)
	}

	if err := os.Rename("./exa_", "./exa"); err != nil {
		panic(err)
	}
}

Testing it

#!/bin/bash -eux
# replace.sh
cp ./replace.sh exa_
mv exa_ exa
go build -o exa
./exa
diff -q replace.sh exa && echo It worked!
# It worked!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment