selfupdate

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2024 License: MIT Imports: 15 Imported by: 1

README

selfupdate

Enable your Golang applications to self update.

Features

  • Tested on Mac, Linux, Arm, and Windows
  • Falls back to full binary update if diff fails to match SHA

QuickStart

Install library and update/patch creation utility

go install github.com/555f/selfupdate/cmd/selfupdatectl@latest

Enable your App to Self Update

go get -u github.com/555f/selfupdate/...

var updater = &selfupdate.Updater{
	CurrentVersion: version, // the current version of your app used to determine if an update is necessary
	// these endpoints can be the same if everything is hosted in the same place
	ApiURL:         "http://updates.yourdomain.com/", // endpoint to get update manifest
	BinURL:         "http://updates.yourdomain.com/", // endpoint to get full binaries
	Dir:            "update/",                        // directory relative to your app to store temporary state files related to selfupdate
	CmdName:        "myapp",                          // your app's name (must correspond to app name hosting the updates)
	// app name allows you to serve updates for multiple apps on the same server/endpoint
}

// go look for an update when your app starts up
go updater.Run()
// your app continues to run...
Push Out and Update
selfupdatectl path-to-your-app the-version
selfupdatectl myapp 1.2

By default this will create a folder in your project called public. You can then rsync or transfer this to your webserver or S3. To change the output directory use -o flag.

If you are cross compiling you can specify a directory:

selfupdatectl /tmp/mybinares/ 1.2

The directory should contain files with the name, $GOOS-$ARCH. Example:

windows-386
darwin-amd64
linux-arm

Update Protocol

Updates are fetched from an HTTP(s) server. AWS S3 or static hosting can be used. A JSON manifest file is pulled first which points to the wanted version (usually latest) and matching metadata. SHA256 hash is currently the only metadata but new fields may be added here like signatures. selfupdate isn't aware of any versioning schemes. It doesn't know major/minor versions. It just knows the target version by name and can apply diffs based on current version and version you wish to move to. For example 1.0 to 5.0 or 1.0 to 1.1. You don't even need to use point numbers. You can use hashes, dates, etc for versions.

GET yourserver.com/appname/linux-amd64.json

200 ok
{
	"Version": "2",
	"Sha256": "..." // base64
}

GET fullbins.yourserver.com/appname/1.0/linux-amd64.gz

200 ok
[gzipped executable data]

The only required files are <appname>/<os>-<arch>.json and <appname>/<latest>/<os>-<arch>.gz everything else is optional. If you wanted to you could skip using selfupdate CLI tool and generate these two files manually or with another tool.

Config

Updater Config options:

type Updater struct {
	CurrentVersion string    // Currently running version. `dev` is a special version here and will cause the updater to never update.
	ApiURL         string    // Base URL for API requests (JSON files).
	CmdName        string    // Command name is appended to the ApiURL like http://apiurl/CmdName/. This represents one binary.
	BinURL         string    // Base URL for full binary downloads.
	Dir            string    // Directory to store selfupdate state.
	ForceCheck     bool      // Check for update regardless of cktime timestamp
	CheckTime      int       // Time in hours before next check
	RandomizeTime  int       // Time in hours to randomize with CheckTime
	Requester      Requester // Optional parameter to override existing HTTP request handler
	Info           struct {
		Version string
		Sha256  []byte
	}
	OnSuccessfulUpdate func() // Optional function to run after an update has successfully taken place
}
Restart on update

It is common for an app to want to restart to apply the update. selfupdate gives you a hook to do that but leaves it up to you on how and when to restart as it differs for all apps. If you have a service restart application like Docker or systemd you can simply exit and let the upstream app start/restart your application. Just set the OnSuccessfulUpdate hook:

u.OnSuccessfulUpdate = func() { os.Exit(0) }

Or maybe you have a fancy graceful restart library/func:

u.OnSuccessfulUpdate = func() { gracefullyRestartMyApp() }

State

selfupdate will keep a Go time.Time formatted timestamp in a file named cktime in folder specified by Updater.Dir. This can be useful for debugging to see when the next update can be applied or allow other applications to manipulate it.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrHashMismatch = errors.New("new file hash mismatch after patch")
)

Functions

This section is empty.

Types

type HTTPRequester

type HTTPRequester struct{}

HTTPRequester is the normal requester that is used and does an HTTP to the URL location requested to retrieve the specified data.

func (*HTTPRequester) Fetch

func (httpRequester *HTTPRequester) Fetch(url string) (io.ReadCloser, error)

Fetch will return an HTTP request to the specified url and return the body of the result. An error will occur for a non 200 status code.

type Requester

type Requester interface {
	Fetch(url string) (io.ReadCloser, error)
}

Requester interface allows developers to customize the method in which requests are made to retrieve the version and binary.

type Updater

type Updater struct {
	CurrentVersion string    // Currently running version. `dev` is a special version here and will cause the updater to never update.
	ApiURL         string    // Base URL for API requests (JSON files).
	CmdName        string    // Command name is appended to the ApiURL like http://apiurl/CmdName/. This represents one binary.
	BinURL         string    // Base URL for full binary downloads.
	Dir            string    // Directory to store selfupdate state.
	ForceCheck     bool      // Check for update regardless of cktime timestamp
	CheckTime      int       // Time in hours before next check
	RandomizeTime  int       // Time in hours to randomize with CheckTime
	Requester      Requester // Optional parameter to override existing HTTP request handler
	Info           struct {
		Version string
		Sha256  []byte
	}
	OnSuccessfulUpdate func() // Optional function to run after an update has successfully taken place
}

Updater is the configuration and runtime data for doing an update.

Note that ApiURL, BinURL and DiffURL should have the same value if all files are available at the same location.

Example:

updater := &selfupdate.Updater{
	CurrentVersion: version,
	ApiURL:         "http://updates.yourdomain.com/",
	BinURL:         "http://updates.yourdownmain.com/",
	DiffURL:        "http://updates.yourdomain.com/",
	Dir:            "update/",
	CmdName:        "myapp", // app name
}
if updater != nil {
	go updater.Run()
}

func (*Updater) ClearUpdateState

func (u *Updater) ClearUpdateState()

ClearUpdateState writes current time to state file

func (*Updater) NextUpdate

func (u *Updater) NextUpdate() time.Time

NextUpdate returns the next time update should be checked

func (*Updater) Run

func (u *Updater) Run() error

BackgroundRun starts the update check and apply cycle.

func (*Updater) SetUpdateTime

func (u *Updater) SetUpdateTime() bool

SetUpdateTime writes the next update time to the state file

func (*Updater) Update

func (u *Updater) Update() error

Update initiates the self update process

func (*Updater) UpdateAvailable

func (u *Updater) UpdateAvailable() (string, error)

UpdateAvailable checks if update is available and returns version

func (*Updater) WantUpdate

func (u *Updater) WantUpdate() bool

WantUpdate returns boolean designating if an update is desired. If the app's version is `dev` WantUpdate will return false. If u.ForceCheck is true or cktime is after now WantUpdate will return true.

Directories

Path Synopsis
cmd
example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL