2017-12-25 07:32:28 +00:00
Self-Update Mechanism for Go Commands using GitHub
==================================================
2017-12-30 05:14:08 +00:00
[![GoDoc Badge][]][GoDoc]
[![TravisCI Status][]][TravisCI]
[![AppVeyor Status][]][AppVeyor]
[![Codecov Status][]][Codecov]
2017-12-25 07:32:28 +00:00
[go-github-selfupdate][] is a Go library to provide self-update mechanism to command line tools.
2017-12-30 02:45:47 +00:00
Go does not provide the way to install/update the stable version of tools. By default, Go command line tools are updated
2017-12-25 07:32:28 +00:00
- using `go get -u` (updating to HEAD)
- using system's package manager (depending on the platform)
2017-12-30 02:45:47 +00:00
- downloading executables from GitHub release page manually
2017-12-25 07:32:28 +00:00
By using this library, you will get 4th choice:
2017-12-30 02:45:47 +00:00
- from your command line tool directly (and automatically)
2017-12-25 07:32:28 +00:00
2017-12-30 02:45:47 +00:00
go-github-selfupdate detects the information of the latest release via [GitHub Releases API][] and check the current version.
If newer version than itself is detected, it downloads released binary from GitHub and replaces itself.
2017-12-25 07:32:28 +00:00
2017-12-30 02:45:47 +00:00
- Automatically detects the latest version of released binary on GitHub
- Retrieve the proper binary for the OS and arch where the binary is running
- Update the binary with rollback support on failure
2017-12-30 05:14:08 +00:00
- Tested on Linux, macOS and Windows (using Travis CI and AppVeyor)
2017-12-30 02:45:47 +00:00
- Many archive and compression formats are supported (zip, gzip, tar)
2017-12-25 07:32:28 +00:00
[go-github-selfupdate]: https://github.com/rhysd/go-github-selfupdate
[GitHub Releases API]: https://developer.github.com/v3/repos/releases/
2017-12-30 02:45:47 +00:00
## Try Out Example
2017-12-30 05:27:31 +00:00
Example to understand what this library does is prepared as [CLI ](./cmd/selfupdate-example/main.go ).
Install it at first.
```
$ go get -u github.com/rhysd/go-github-selfupdate/tree/master/cmd/selfupdate-example
```
And check the version by `-version` . `-help` flag is also available to know all flags.
```
$ selfupdate-example -version
```
It should show `v1.2.3` .
Then run `-selfupdate`
```
$ selfupdate-example -selfupdate
```
It should replace itself and finally shows a message containing release notes.
Please check the binary version is updated to `v1.2.4` with `-version` . The binary is up-to-date. So running `-selfupdate` again only shows 'Current binary is the latest version'.
2017-12-30 06:42:13 +00:00
### Real World Examples
Following tools are using this library.
- [dot-github ](https://github.com/rhysd/dot-github )
- [dotfiles ](https://github.com/rhysd/dotfiles )
- [git-clone-all ](https://github.com/rhysd/git-clone-all )
2017-12-30 02:45:47 +00:00
2017-12-25 07:32:28 +00:00
## Usage
2017-12-30 02:45:47 +00:00
### Code Usage
2017-12-25 07:32:28 +00:00
It provides `selfupdate` package.
2017-12-30 04:12:56 +00:00
- `selfupdate.UpdateSelf()` : Detect the latest version of itself and run self update.
- `selfupdate.UpdateCommand()` : Detect the latest version of given repository and update given command.
- `selfupdate.DetectLatest()` : Detect the latest version of given repository.
- `selfupdate.UpdateTo()` : Update given command to the binary hosted on given URL.
2017-12-30 02:45:47 +00:00
Following is the easiest way to use this package.
2017-12-25 07:32:28 +00:00
```go
import (
"log"
2017-12-30 04:12:56 +00:00
"github.com/blang/semver"
2017-12-26 02:45:08 +00:00
"github.com/rhysd/go-github-selfupdate/selfupdate"
2017-12-25 07:32:28 +00:00
)
2017-12-30 02:45:47 +00:00
const version = "1.2.3"
func doSelfUpdate() {
v := semver.MustParse(version)
latest, err := selfupdate.UpdateSelf(v, "myname/myrepo")
2017-12-25 07:32:28 +00:00
if err != nil {
2017-12-30 02:45:47 +00:00
log.Println("Binary update failed:", err)
2017-12-25 07:32:28 +00:00
return
}
2017-12-30 02:45:47 +00:00
if latest.Version.Equals(v) {
// latest version is the same as current version. It means current binary is up to date.
2017-12-25 07:32:28 +00:00
log.Println("Current binary is the latest version", version)
} else {
2017-12-30 02:45:47 +00:00
log.Println("Successfully updated to version", latest.Version)
2017-12-30 04:12:56 +00:00
log.Println("Release note:\n", latest.ReleaseNotes)
2017-12-25 07:32:28 +00:00
}
}
```
2017-12-30 04:12:56 +00:00
Following asks user to update or not.
```go
import (
"bufio"
"github.com/blang/semver"
"github.com/rhysd/go-github-selfupdate/selfupdate"
"log"
"os"
)
const version = "1.2.3"
func confirmAndSelfUpdate() {
latest, found, err := selfupdate.DetectLatest("owner/repo")
if err != nil {
log.Println("Error occurred while detecting version:", err)
return
}
v := semver.MustParse(version)
if !found || latest.Version.Equals(v) {
log.Println("Current version is the latest")
return
}
fmt.Print("Do you want to update to", latest.Version, "? (y/n): ")
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err != nil || (input != "y\n" && input != "n\n") {
log.Println("Invalid input")
return
}
if input == "n\n" {
return
}
if err := selfupdate.UpdateTo(latest.AssetURL, os.Args[0]); err != nil {
log.Println("Error occurred while updating binary:", err)
return
}
log.Println("Successfully updated to version", latest.Version)
}
```
2017-12-25 07:32:28 +00:00
Please see [the documentation page][GoDoc] for more detail.
### Naming Rules of Released Binaries
go-github-selfupdate assumes that released binaries are put for each combination of platforms and archs.
2017-12-30 02:45:47 +00:00
Binaries for each platform can be easily built using tools like [gox][]
2017-12-25 07:32:28 +00:00
2017-12-30 02:45:47 +00:00
You need to put the binaries with the following format.
```
{cmd}_{goos}_{goarch}{.ext}
```
`{cmd}` is a name of command.
`{goos}` and `{goarch}` are the platform and the arch type of the binary.
`{.ext}` is a file extension. go-github-selfupdate supports `.zip` , `.gzip` and `.tar.gz` .
You can also use blank and it means binary is not compressed.
If you compress binary, uncompressed directory or file must contain the executable named `{cmd}` .
And you can also use `-` for separator instead of `_` if you like.
For example, if your command name is `foo-bar` , one of followings is expected to be put in release
page on GitHub as binary for platform `linux` and arch `amd64` .
2017-12-25 07:32:28 +00:00
- `foo-bar_linux_amd64` (executable)
2017-12-30 02:45:47 +00:00
- `foo-bar_linux_amd64.zip` (zip file containing `foo-bar` )
- `foo-bar_linux_amd64.tar.gz` (tar file containing `foo-bar` )
- `foo-bar_linux_amd64.gzip` (gzip file of the executable `foo-bar` )
- `foo-bar-linux-amd64.tar.gz` (`-` is also ok for separator)
2017-12-30 03:52:59 +00:00
To archive the executable directly on Windows, `.exe` can be added before file extension like
`foo-bar_windows_amd64.exe.zip` .
2017-12-30 02:45:47 +00:00
[gox]: https://github.com/mitchellh/gox
2017-12-25 07:32:28 +00:00
2017-12-30 02:45:47 +00:00
### Naming Rules of Versions (=Git Tags)
2017-12-25 07:32:28 +00:00
2017-12-30 02:45:47 +00:00
go-github-selfupdate searches binaries' versions via Git tag names (not a release title).
When your tool's version is `1.2.3` , you should use the version number for tag of the Git
repository (i.e. `1.2.3` or `v1.2.3` ).
This library assumes you adopt [semantic versioning][]. It is necessary for comparing versions
systematically.
Prefix before version number `\d+\.\d+\.\d+` is automatically omitted. For example, `ver1.2.3` or
`release-1.2.3` are also ok.
Tags which don't contain a version number are ignored (i.e. `nightly` ). And releases marked as `pre-release`
are also ignored.
2017-12-25 07:32:28 +00:00
2017-12-30 03:31:07 +00:00
[semantic versioning]: https://semver.org/
2017-12-25 07:32:28 +00:00
### Structure of Releases
In summary, structure of releases on GitHub looks like:
- `v1.2.0`
2017-12-30 02:45:47 +00:00
- `foo-bar-linux-amd64.tar.gz`
- `foo-bar-linux-386.tar.gz`
- `foo-bar-darwin-amd64.tar.gz`
2017-12-25 07:32:28 +00:00
- `foo-bar-windows-amd64.zip`
- ... (Other binaries for v1.2.0)
- `v1.1.3`
2017-12-30 02:45:47 +00:00
- `foo-bar-linux-amd64.tar.gz`
- `foo-bar-linux-386.tar.gz`
- `foo-bar-darwin-amd64.tar.gz`
2017-12-25 07:32:28 +00:00
- `foo-bar-windows-amd64.zip`
- ... (Other binaries for v1.1.3)
- ... (older versions)
2017-12-30 02:45:47 +00:00
Tags which don't contain a version number are ignored (i.e. `nightly` ). And releases marked as `pre-release` are also ignored.
### Debugging
This library can output logs for debugging. By default, logger is disabled.
You can enable the logger by following and can know the details of the self update.
```go
selfupdate.EnableLog()
```
2017-12-25 07:32:28 +00:00
## Dependencies
2017-12-30 02:45:47 +00:00
This library utilizes [go-github][] to retrieve the information of releases and [go-update][] to replace
current binary and [semver][] to compare versions.
2017-12-25 07:32:28 +00:00
> Copyright (c) 2013 The go-github AUTHORS. All rights reserved.
> Copyright 2015 Alan Shreve
> Copyright (c) 2014 Benedikt Lang <github at benediktlang.de>
[go-github]: https://github.com/google/go-github
2017-12-26 02:48:09 +00:00
[go-update]: https://github.com/inconshreveable/go-update
2017-12-25 07:32:28 +00:00
[semver]: https://github.com/blang/semver
2017-12-30 02:45:47 +00:00
## What is the different from [tj/go-update][]?
2017-12-30 03:13:58 +00:00
This library goal is the same as tj/go-update, but it's different in following points.
tj/go-update:
- does not support Windows
- only allows `v` for version prefix
- does not ignore pre-release
- has [only a few tests ](https://github.com/tj/go-update/blob/master/update_test.go )
2017-12-30 02:45:47 +00:00
2017-12-30 03:55:12 +00:00
[tj/go-update]: https://github.com/tj/go-update
## License
Distributed under the [MIT License ](LICENSE )
2017-12-30 02:45:47 +00:00
2017-12-30 05:14:08 +00:00
[GoDoc Badge]: https://godoc.org/github.com/rhysd/go-github-selfupdate/selfupdate?status.svg
2017-12-30 03:31:07 +00:00
[GoDoc]: https://godoc.org/github.com/rhysd/go-github-selfupdate/selfupdate
2017-12-30 05:14:08 +00:00
[TravisCI Status]: https://travis-ci.org/rhysd/go-github-selfupdate.svg?branch=master
[TravisCI]: https://travis-ci.org/rhysd/go-github-selfupdate
[AppVeyor Status]: https://ci.appveyor.com/api/projects/status/1tpyd9q9tw3ime5u/branch/master?svg=true
[AppVeyor]: https://ci.appveyor.com/project/rhysd/go-github-selfupdate/branch/master
[Codecov Status]: https://codecov.io/gh/rhysd/go-github-selfupdate/branch/master/graph/badge.svg
[Codecov]: https://codecov.io/gh/rhysd/go-github-selfupdate