selfupdate

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2024 License: MIT Imports: 37 Imported by: 30

README

Self-Update library for Github, Gitea and Gitlab hosted applications in Go

Godoc reference Build codecov Bugs Reliability Rating Maintainability Rating Security Rating Vulnerabilities

Introduction

go-selfupdate detects the information of the latest release via a source provider and checks the current version. If a newer version than itself is detected, it downloads the released binary from the source provider and replaces itself.

  • Automatically detect the latest version of released binary on the source provider
  • Retrieve the proper binary for the OS and arch where the binary is running
  • Update the binary with rollback support on failure
  • Tested on Linux, macOS and Windows
  • Support for different versions of ARM architecture
  • Support macOS universal binaries
  • Many archive and compression formats are supported (zip, tar, gzip, xz, bzip2)
  • Support private repositories
  • Support hash, signature validation

Three source providers are available:

  • GitHub
  • Gitea
  • Gitlab

This library started as a fork of https://github.com/rhysd/go-github-selfupdate. A few things have changed from the original implementation:

  • don't expose an external semver.Version type, but provide the same functionality through the API: LessThan, Equal and GreaterThan
  • use an interface to send logs (compatible with standard log.Logger)
  • able to detect different ARM CPU architectures (the original library wasn't working on my different versions of raspberry pi)
  • support for assets compressed with bzip2 (.bz2)
  • can use a single file containing the sha256 checksums for all the files (one per line)
  • separate the provider and the updater, so we can add more providers (Github, Gitea, Gitlab, etc.)
  • return well defined wrapped errors that can be checked with errors.Is(err error, target error)

Example

Here's an example how to use the library for an application to update itself

func update(version string) error {
	latest, found, err := selfupdate.DetectLatest(context.Background(), selfupdate.ParseSlug("creativeprojects/resticprofile"))
	if err != nil {
		return fmt.Errorf("error occurred while detecting version: %w", err)
	}
	if !found {
		return fmt.Errorf("latest version for %s/%s could not be found from github repository", runtime.GOOS, runtime.GOARCH)
	}

	if latest.LessOrEqual(version) {
		log.Printf("Current version (%s) is the latest", version)
		return nil
	}

	exe, err := selfupdate.ExecutablePath()
	if err != nil {
		return errors.New("could not locate executable path")
	}
	if err := selfupdate.UpdateTo(context.Background(), latest.AssetURL, latest.AssetName, exe); err != nil {
		return fmt.Errorf("error occurred while updating binary: %w", err)
	}
	log.Printf("Successfully updated to version %s", latest.Version())
	return nil
}

Upgrade from v0+ to v1

Version v1+ has a stable API. It is slightly different from the API of versions 0+.

Repository

Some functions needed a couple owner/repo and some other a single string called slug. These have been replaced by a Repository.

Two constructors are available:

ParseSlug

Parses a slug string like owner/repository_name

func ParseSlug(slug string) RepositorySlug
NewRepositorySlug

Creates a repository from both owner and repo strings

func NewRepositorySlug(owner, repo string) RepositorySlug
NewRepositoryID (GitLab only)

GitLab can also refer to a repository via its internal ID. This constructor can be used with a numeric repository ID.

func NewRepositoryID(id int) RepositoryID
Context

All methods are now accepting a context as their first parameter. You can use it to cancel a long running operation.

Package functions

v0 v1
UpdateTo(assetURL, assetFileName, cmdPath string) error UpdateTo(ctx context.Context, assetURL, assetFileName, cmdPath string) error
DetectLatest(slug string) (*Release, bool, error) DetectLatest(ctx context.Context, repository Repository) (*Release, bool, error)
DetectVersion(slug string, version string) (*Release, bool, error) DetectVersion(ctx context.Context, repository Repository, version string) (*Release, bool, error)
UpdateCommand(cmdPath string, current string, slug string) (*Release, error) UpdateCommand(ctx context.Context, cmdPath string, current string, repository Repository) (*Release, error)
UpdateSelf(current string, slug string) (*Release, error) UpdateSelf(ctx context.Context, current string, repository Repository) (*Release, error)

Methods on Source interface

v0 v1
ListReleases(owner, repo string) ([]SourceRelease, error) ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error)
DownloadReleaseAsset(owner, repo string, releaseID, id int64) (io.ReadCloser, error) DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error)

Methods on Updater struct

v0 v1
DetectLatest(slug string) (release *Release, found bool, err error) DetectLatest(ctx context.Context, repository Repository) (release *Release, found bool, err error)
DetectVersion(slug string, version string) (release *Release, found bool, err error) DetectVersion(ctx context.Context, repository Repository, version string) (release *Release, found bool, err error)
UpdateCommand(cmdPath string, current string, slug string) (*Release, error) UpdateCommand(ctx context.Context, cmdPath string, current string, repository Repository) (*Release, error)
UpdateSelf(current string, slug string) (*Release, error) UpdateSelf(ctx context.Context, current string, repository Repository) (*Release, error)
UpdateTo(rel *Release, cmdPath string) error UpdateTo(ctx context.Context, rel *Release, cmdPath string) error

Naming Rules of Released Binaries

go-selfupdate assumes that released binaries are put for each combination of platforms and architectures. Binaries for each platform can be easily built using tools like goreleaser

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-selfupdate supports .zip, .gzip, .bz2, .tar.gz and .tar.xz. 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.

  • foo-bar_linux_amd64 (executable)
  • foo-bar_linux_amd64.zip (zip file)
  • foo-bar_linux_amd64.tar.gz (tar file)
  • foo-bar_linux_amd64.xz (xzip file)
  • foo-bar-linux-amd64.tar.gz (- is also ok for separator)

If you compress and/or archive your release asset, it must contain an executable named one of followings:

  • foo-bar (only command name)
  • foo-bar_linux_amd64 (full name)
  • foo-bar-linux-amd64 (- is also ok for separator)

To archive the executable directly on Windows, .exe can be added before file extension like foo-bar_windows_amd64.exe.zip.

Naming Rules of Versions (=Git Tags)

go-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.

Structure of Releases

In summary, structure of releases on GitHub looks like:

  • v1.2.0
    • foo-bar-linux-amd64.tar.gz
    • foo-bar-linux-386.tar.gz
    • foo-bar-darwin-amd64.tar.gz
    • foo-bar-windows-amd64.zip
    • ... (Other binaries for v1.2.0)
  • v1.1.3
    • foo-bar-linux-amd64.tar.gz
    • foo-bar-linux-386.tar.gz
    • foo-bar-darwin-amd64.tar.gz
    • foo-bar-windows-amd64.zip
    • ... (Other binaries for v1.1.3)
  • ... (older versions)

Special case for ARM architecture

If you're using goreleaser targeting ARM CPUs, it will use the version of the ARM architecture as a name:

  • armv5
  • armv6
  • armv7

go-selfupdate will check which architecture was used to build the current binary. Please note it's not detecting the hardware, but the binary target instead. If you run an armv6 binary on an armv7 CPU, it will keep armv6 as a target.

As a rule, it will search for a binary with the same architecture first, then try the architectures below if available, and as a last resort will try a simple arm architecture tag.

So if you're running a armv6 binary, it will try these targets in order:

  • armv6
  • armv5
  • arm

More information on targeting ARM cpu can be found here: GoArm

Hash or Signature Validation

go-selfupdate supports hash or signature validation of the downloaded files. It comes with support for sha256 hashes or ECDSA signatures. If you need something different, you can implement the Validator interface with your own validation mechanism:

// Validator represents an interface which enables additional validation of releases.
type Validator interface {
	// Validate validates release bytes against an additional asset bytes.
	// See SHAValidator or ECDSAValidator for more information.
	Validate(filename string, release, asset []byte) error
	// GetValidationAssetName returns the additional asset name containing the validation checksum.
	// The asset containing the checksum can be based on the release asset name
	// Please note if the validation file cannot be found, the DetectLatest and DetectVersion methods
	// will fail with a wrapped ErrValidationAssetNotFound error
	GetValidationAssetName(releaseFilename string) string
}

SHA256

To verify the integrity by SHA256, generate a hash sum and save it within a file which has the same naming as original file with the suffix .sha256. For e.g. use sha256sum, the file selfupdate/testdata/foo.zip.sha256 is generated with:

sha256sum foo.zip > foo.zip.sha256

ECDSA

To verify the signature by ECDSA generate a signature and save it within a file which has the same naming as original file with the suffix .sig. For e.g. use openssl, the file selfupdate/testdata/foo.zip.sig is generated with:

openssl dgst -sha256 -sign Test.pem -out foo.zip.sig foo.zip

go-selfupdate makes use of go internal crypto package. Therefore the private key has to be compatible with FIPS 186-3.

Using a single checksum file for all your assets

Tools like goreleaser produce a single checksum file for all your assets. A Validator is provided out of the box for this case:

updater, _ := NewUpdater(Config{Validator: &ChecksumValidator{UniqueFilename: "checksums.txt"}})

macOS universal binaries

You can ask the updater to choose a macOS universal binary as a fallback if the native architecture wasn't found.

You need to provide the architecture name for the universal binary in the Config struct:

updater, _ := NewUpdater(Config{UniversalArch: "all"})

Default is empty, which means no fallback.

Other providers than Github

This library can be easily extended by providing a new source and release implementation for any git provider Currently implemented are

  • Github (default)
  • Gitea
  • Gitlab

GitLab

Support for GitLab landed in version 1.0.0.

To be able to download assets from a private instance of GitLab, you have to publish your files to the Generic Package Registry.

If you're using goreleaser, you just need to add this option:

# .goreleaser.yml
gitlab_urls:
  use_package_registry: true

See goreleaser documentation for more information.

Example:

func update() {
	source, err := selfupdate.NewGitLabSource(selfupdate.GitLabConfig{
		BaseURL: "https://private.instance.on.gitlab.com/",
	})
	if err != nil {
		log.Fatal(err)
	}
	updater, err := selfupdate.NewUpdater(selfupdate.Config{
		Source:    source,
		Validator: &selfupdate.ChecksumValidator{UniqueFilename: "checksums.txt"}, // checksum from goreleaser
	})
	if err != nil {
		log.Fatal(err)
	}
	release, found, err := updater.DetectLatest(context.Background(), selfupdate.NewRepositorySlug("owner", "cli-tool"))
	if err != nil {
		log.Fatal(err)
	}
	if !found {
		log.Print("Release not found")
		return
	}
	fmt.Printf("found release %s\n", release.Version())

	exe, err := selfupdate.ExecutablePath()
	if err != nil {
		return errors.New("could not locate executable path")
	}
	err = updater.UpdateTo(context.Background(), release, exe)
	if err != nil {
		log.Fatal(err)
	}
}

Http Based Repository

Support for http based repositories landed in version 1.4.0.

The HttpSource is designed to work with repositories built using goreleaser-http-repo-builder. This provides a simple way to add self-update support to software that is not open source, allowing you to host your own updates. It requires that you still use the owner/project url style, and you can set custom headers to be used with requests to authenticate.

Example:

If your repository is at example.com/repo/project, then you'd use the following example.

func update() {
	source, err := selfupdate.NewHttpSource(selfupdate.HttpConfig{
		BaseURL: "https://example.com/",
	})
	if err != nil {
		log.Fatal(err)
	}
	updater, err := selfupdate.NewUpdater(selfupdate.Config{
		Source:    source,
		Validator: &selfupdate.ChecksumValidator{UniqueFilename: "checksums.txt"}, // checksum from goreleaser
	})
	if err != nil {
		log.Fatal(err)
	}
	release, found, err := updater.DetectLatest(context.Background(), selfupdate.NewRepositorySlug("repo", "project"))
	if err != nil {
		log.Fatal(err)
	}
	if !found {
		log.Print("Release not found")
		return
	}
	fmt.Printf("found release %s\n", release.Version())

	exe, err := selfupdate.ExecutablePath()
	if err != nil {
		return errors.New("could not locate executable path")
	}
	err = updater.UpdateTo(context.Background(), release, exe)
	if err != nil {
		log.Fatal(err)
	}
}

This work is heavily based on:

Documentation

Overview

go-selfupdate detects the information of the latest release via GitHub Releases API and checks the current version. If newer version than itself is detected, it downloads released binary from GitHub and replaces itself.

- 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

- Tested on Linux, macOS and Windows

- Many archive and compression formats are supported (zip, gzip, xzip, bzip2, tar)

There are some naming rules. Please read following links.

Naming Rules of Released Binaries:

https://github.com/creativeprojects/go-selfupdate#naming-rules-of-released-binaries

Naming Rules of Git Tags:

https://github.com/creativeprojects/go-selfupdate#naming-rules-of-versions-git-tags

This package is hosted on GitHub:

https://github.com/creativeprojects/go-selfupdate

Small CLI tools as wrapper of this library are available also:

https://github.com/creativeprojects/go-selfupdate/cmd/detect-latest-release
https://github.com/creativeprojects/go-selfupdate/cmd/go-get-release

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNotSupported                = errors.New("operation not supported")
	ErrInvalidSlug                 = errors.New("invalid slug format, expected 'owner/name'")
	ErrIncorrectParameterOwner     = errors.New("incorrect parameter \"owner\"")
	ErrIncorrectParameterRepo      = errors.New("incorrect parameter \"repo\"")
	ErrInvalidID                   = errors.New("invalid repository ID, expected 'owner/name' but found number")
	ErrInvalidRelease              = errors.New("invalid release (nil argument)")
	ErrAssetNotFound               = errors.New("asset not found")
	ErrValidationAssetNotFound     = errors.New("validation file not found")
	ErrValidatorNotFound           = errors.New("file did not match a configured validator")
	ErrIncorrectChecksumFile       = errors.New("incorrect checksum file format")
	ErrChecksumValidationFailed    = errors.New("sha256 validation failed")
	ErrHashNotFound                = errors.New("hash not found in checksum file")
	ErrECDSAValidationFailed       = errors.New("ECDSA signature verification failed")
	ErrInvalidECDSASignature       = errors.New("invalid ECDSA signature")
	ErrInvalidPGPSignature         = errors.New("invalid PGP signature")
	ErrPGPKeyRingNotSet            = errors.New("PGP key ring not set")
	ErrCannotDecompressFile        = errors.New("failed to decompress")
	ErrExecutableNotFoundInArchive = errors.New("executable not found")
)

Possible errors returned

Functions

func DecompressCommand

func DecompressCommand(src io.Reader, url, cmd, os, arch string) (io.Reader, error)

DecompressCommand decompresses the given source. Archive and compression format is automatically detected from 'url' parameter, which represents the URL of asset, or simply a filename (with an extension). This returns a reader for the decompressed command given by 'cmd'. '.zip', '.tar.gz', '.tar.xz', '.tgz', '.gz', '.bz2' and '.xz' are supported.

These wrapped errors can be returned:

  • ErrCannotDecompressFile
  • ErrExecutableNotFoundInArchive

func ExecutablePath added in v1.3.0

func ExecutablePath() (string, error)

func IsDarwinUniversalBinary added in v1.3.0

func IsDarwinUniversalBinary(filename string) bool

IsDarwinUniversalBinary checks if the file is a universal binary (also called a fat binary).

func SetLogger

func SetLogger(logger Logger)

SetLogger redirects all logs to the logger defined in parameter. By default logs are not sent anywhere.

Example
// you can plug-in any logger providing the 2 methods Print and Printf
// the default log.Logger satisfies the interface
logger := stdlog.New(os.Stdout, "selfupdate ", 0)
SetLogger(logger)
Output:

func UpdateTo

func UpdateTo(ctx context.Context, assetURL, assetFileName, cmdPath string) error

UpdateTo downloads an executable from assetURL and replaces the current binary with the downloaded one. This function is low-level API to update the binary. Because it does not use a source provider and downloads asset directly from the URL via HTTP, this function is not available to update a release for private repositories. cmdPath is a file path to command executable.

Types

type ChecksumValidator

type ChecksumValidator struct {
	// UniqueFilename is the name of the global file containing all the checksums
	// Usually "checksums.txt", "SHA256SUMS", etc.
	UniqueFilename string
}

ChecksumValidator is a SHA256 checksum validator where all the validation hash are in a single file (one per line)

func (*ChecksumValidator) GetValidationAssetName

func (v *ChecksumValidator) GetValidationAssetName(releaseFilename string) string

GetValidationAssetName returns the unique asset name for SHA256 validation.

func (*ChecksumValidator) Validate

func (v *ChecksumValidator) Validate(filename string, release, asset []byte) error

Validate the SHA256 sum of the release against the contents of an additional asset file containing all the checksums (one file per line).

type Config

type Config struct {
	// Source where to load the releases from (example: GitHubSource).
	Source Source
	// Validator represents types which enable additional validation of downloaded release.
	Validator Validator
	// Filters are regexp used to filter on specific assets for releases with multiple assets.
	// An asset is selected if it matches any of those, in addition to the regular tag, os, arch, extensions.
	// Please make sure that your filter(s) uniquely match an asset.
	Filters []string
	// OS is set to the value of runtime.GOOS by default, but you can force another value here.
	OS string
	// Arch is set to the value of runtime.GOARCH by default, but you can force another value here.
	Arch string
	// Arm 32bits version. Valid values are 0 (unknown), 5, 6 or 7. Default is detected value (if available).
	Arm uint8
	// Arch name for macOS universal binary. Default to none.
	// If set, the updater will only pick the universal binary if the Arch is not found.
	UniversalArch string
	// Draft permits an upgrade to a "draft" version (default to false).
	Draft bool
	// Prerelease permits an upgrade to a "pre-release" version (default to false).
	Prerelease bool
	// To prevent automatic removal of the old binary, and allow you to test an update prior to manual removal.
	OldSavePath string
}

Config represents the configuration of self-update.

type ECDSAValidator

type ECDSAValidator struct {
	PublicKey *ecdsa.PublicKey
}

ECDSAValidator specifies a ECDSA validator for additional file validation before updating.

func (*ECDSAValidator) GetValidationAssetName

func (v *ECDSAValidator) GetValidationAssetName(releaseFilename string) string

GetValidationAssetName returns the asset name for ECDSA validation.

func (*ECDSAValidator) Validate

func (v *ECDSAValidator) Validate(filename string, input, signature []byte) error

Validate checks the ECDSA signature of the release against the signature contained in an additional asset file.

func (*ECDSAValidator) WithPublicKey added in v1.0.0

func (v *ECDSAValidator) WithPublicKey(pemData []byte) *ECDSAValidator

WithPublicKey is a convenience method to set PublicKey from a PEM encoded ECDSA certificate

type GitHubAsset

type GitHubAsset struct {
	// contains filtered or unexported fields
}

func NewGitHubAsset

func NewGitHubAsset(from *github.ReleaseAsset) *GitHubAsset

func (*GitHubAsset) GetBrowserDownloadURL

func (a *GitHubAsset) GetBrowserDownloadURL() string

func (*GitHubAsset) GetID

func (a *GitHubAsset) GetID() int64

func (*GitHubAsset) GetName

func (a *GitHubAsset) GetName() string

func (*GitHubAsset) GetSize

func (a *GitHubAsset) GetSize() int

type GitHubConfig

type GitHubConfig struct {
	// APIToken represents GitHub API token. If it's not empty, it will be used for authentication of GitHub API
	APIToken string
	// EnterpriseBaseURL is a base URL of GitHub API. If you want to use this library with GitHub Enterprise,
	// please set "https://{your-organization-address}/api/v3/" to this field.
	EnterpriseBaseURL string
	// EnterpriseUploadURL is a URL to upload stuffs to GitHub Enterprise instance. This is often the same as an API base URL.
	// So if this field is not set and EnterpriseBaseURL is set, EnterpriseBaseURL is also set to this field.
	EnterpriseUploadURL string
	// Deprecated: Context option is no longer used
	Context context.Context
}

GitHubConfig is an object to pass to NewGitHubSource

type GitHubRelease

type GitHubRelease struct {
	// contains filtered or unexported fields
}

func NewGitHubRelease

func NewGitHubRelease(from *github.RepositoryRelease) *GitHubRelease

func (*GitHubRelease) GetAssets

func (r *GitHubRelease) GetAssets() []SourceAsset

func (*GitHubRelease) GetDraft

func (r *GitHubRelease) GetDraft() bool

func (*GitHubRelease) GetID added in v0.5.0

func (a *GitHubRelease) GetID() int64

func (*GitHubRelease) GetName

func (r *GitHubRelease) GetName() string

func (*GitHubRelease) GetPrerelease

func (r *GitHubRelease) GetPrerelease() bool

func (*GitHubRelease) GetPublishedAt

func (r *GitHubRelease) GetPublishedAt() time.Time

func (*GitHubRelease) GetReleaseNotes

func (r *GitHubRelease) GetReleaseNotes() string

func (*GitHubRelease) GetTagName

func (r *GitHubRelease) GetTagName() string

func (*GitHubRelease) GetURL

func (r *GitHubRelease) GetURL() string

type GitHubSource

type GitHubSource struct {
	// contains filtered or unexported fields
}

GitHubSource is used to load release information from GitHub

func NewGitHubSource

func NewGitHubSource(config GitHubConfig) (*GitHubSource, error)

NewGitHubSource creates a new GitHubSource from a config object. It initializes a GitHub API client. If you set your API token to the $GITHUB_TOKEN environment variable, the client will use it. You can pass an empty GitHubSource{} to use the default configuration The function will return an error if the GitHub Enterprise URLs in the config object cannot be parsed

func (*GitHubSource) DownloadReleaseAsset

func (s *GitHubSource) DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error)

DownloadReleaseAsset downloads an asset from a release. It returns an io.ReadCloser: it is your responsibility to Close it.

func (*GitHubSource) ListReleases

func (s *GitHubSource) ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error)

ListReleases returns all available releases

type GitLabAsset added in v1.0.0

type GitLabAsset struct {
	// contains filtered or unexported fields
}

func NewGitLabAsset added in v1.0.0

func NewGitLabAsset(from *gitlab.ReleaseLink) *GitLabAsset

func (*GitLabAsset) GetBrowserDownloadURL added in v1.0.0

func (a *GitLabAsset) GetBrowserDownloadURL() string

func (*GitLabAsset) GetID added in v1.0.0

func (a *GitLabAsset) GetID() int64

func (*GitLabAsset) GetName added in v1.0.0

func (a *GitLabAsset) GetName() string

func (*GitLabAsset) GetSize added in v1.0.0

func (a *GitLabAsset) GetSize() int

type GitLabConfig added in v1.0.0

type GitLabConfig struct {
	// APIToken represents GitLab API token. If it's not empty, it will be used for authentication for the API
	APIToken string
	// BaseURL is a base URL of your private GitLab instance
	BaseURL string
}

GitLabConfig is an object to pass to NewGitLabSource

type GitLabRelease added in v1.0.0

type GitLabRelease struct {
	// contains filtered or unexported fields
}

func NewGitLabRelease added in v1.0.0

func NewGitLabRelease(from *gitlab.Release) *GitLabRelease

func (*GitLabRelease) GetAssets added in v1.0.0

func (r *GitLabRelease) GetAssets() []SourceAsset

func (*GitLabRelease) GetDraft added in v1.0.0

func (r *GitLabRelease) GetDraft() bool

func (*GitLabRelease) GetID added in v1.0.0

func (r *GitLabRelease) GetID() int64

func (*GitLabRelease) GetName added in v1.0.0

func (r *GitLabRelease) GetName() string

func (*GitLabRelease) GetPrerelease added in v1.0.0

func (r *GitLabRelease) GetPrerelease() bool

func (*GitLabRelease) GetPublishedAt added in v1.0.0

func (r *GitLabRelease) GetPublishedAt() time.Time

func (*GitLabRelease) GetReleaseNotes added in v1.0.0

func (r *GitLabRelease) GetReleaseNotes() string

func (*GitLabRelease) GetTagName added in v1.0.0

func (r *GitLabRelease) GetTagName() string

func (*GitLabRelease) GetURL added in v1.0.0

func (r *GitLabRelease) GetURL() string

type GitLabSource added in v1.0.0

type GitLabSource struct {
	// contains filtered or unexported fields
}

GitLabSource is used to load release information from GitLab

func NewGitLabSource added in v1.0.0

func NewGitLabSource(config GitLabConfig) (*GitLabSource, error)

NewGitLabSource creates a new GitLabSource from a config object. It initializes a GitLab API client. If you set your API token to the $GITLAB_TOKEN environment variable, the client will use it. You can pass an empty GitLabSource{} to use the default configuration The function will return an error if the GitLab Enterprise URLs in the config object cannot be parsed

func (*GitLabSource) DownloadReleaseAsset added in v1.0.0

func (s *GitLabSource) DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error)

DownloadReleaseAsset downloads an asset from a release. It returns an io.ReadCloser: it is your responsibility to Close it.

func (*GitLabSource) ListReleases added in v1.0.0

func (s *GitLabSource) ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error)

ListReleases returns all available releases

type GiteaAsset added in v0.5.0

type GiteaAsset struct {
	// contains filtered or unexported fields
}

func NewGiteaAsset added in v0.5.0

func NewGiteaAsset(from *gitea.Attachment) *GiteaAsset

func (*GiteaAsset) GetBrowserDownloadURL added in v0.5.0

func (a *GiteaAsset) GetBrowserDownloadURL() string

func (*GiteaAsset) GetID added in v0.5.0

func (a *GiteaAsset) GetID() int64

func (*GiteaAsset) GetName added in v0.5.0

func (a *GiteaAsset) GetName() string

func (*GiteaAsset) GetSize added in v0.5.0

func (a *GiteaAsset) GetSize() int

type GiteaConfig added in v0.5.0

type GiteaConfig struct {
	// APIToken represents Gitea API token. If it's not empty, it will be used for authentication for the API
	APIToken string
	// BaseURL is a base URL of your gitea instance. This parameter has NO default value.
	BaseURL string
	// Deprecated: Context option is no longer used
	Context context.Context
}

GiteaConfig is an object to pass to NewGiteaSource

type GiteaRelease added in v0.5.0

type GiteaRelease struct {
	// contains filtered or unexported fields
}

func NewGiteaRelease added in v0.5.0

func NewGiteaRelease(from *gitea.Release) *GiteaRelease

func (*GiteaRelease) GetAssets added in v0.5.0

func (r *GiteaRelease) GetAssets() []SourceAsset

func (*GiteaRelease) GetDraft added in v0.5.0

func (r *GiteaRelease) GetDraft() bool

func (*GiteaRelease) GetID added in v0.5.0

func (r *GiteaRelease) GetID() int64

func (*GiteaRelease) GetName added in v0.5.0

func (r *GiteaRelease) GetName() string

func (*GiteaRelease) GetPrerelease added in v0.5.0

func (r *GiteaRelease) GetPrerelease() bool

func (*GiteaRelease) GetPublishedAt added in v0.5.0

func (r *GiteaRelease) GetPublishedAt() time.Time

func (*GiteaRelease) GetReleaseNotes added in v0.5.0

func (r *GiteaRelease) GetReleaseNotes() string

func (*GiteaRelease) GetTagName added in v0.5.0

func (r *GiteaRelease) GetTagName() string

func (*GiteaRelease) GetURL added in v0.5.0

func (r *GiteaRelease) GetURL() string

type GiteaSource added in v0.5.0

type GiteaSource struct {
	// contains filtered or unexported fields
}

GiteaSource is used to load release information from Gitea

func NewGiteaSource added in v0.5.0

func NewGiteaSource(config GiteaConfig) (*GiteaSource, error)

NewGiteaSource creates a new NewGiteaSource from a config object. It initializes a Gitea API Client. If you set your API token to the $GITEA_TOKEN environment variable, the client will use it. You can pass an empty GiteaSource{} to use the default configuration

func (*GiteaSource) DownloadReleaseAsset added in v0.5.0

func (s *GiteaSource) DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error)

DownloadReleaseAsset downloads an asset from a release. It returns an io.ReadCloser: it is your responsibility to Close it.

func (*GiteaSource) ListReleases added in v0.5.0

func (s *GiteaSource) ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error)

ListReleases returns all available releases

type HttpAsset added in v1.4.0

type HttpAsset struct {
	ID   int64  `yaml:"id"`
	Name string `yaml:"name"`
	Size int    `yaml:"size"`
	URL  string `yaml:"url"`
}

func (*HttpAsset) GetBrowserDownloadURL added in v1.4.0

func (a *HttpAsset) GetBrowserDownloadURL() string

func (*HttpAsset) GetID added in v1.4.0

func (a *HttpAsset) GetID() int64

func (*HttpAsset) GetName added in v1.4.0

func (a *HttpAsset) GetName() string

func (*HttpAsset) GetSize added in v1.4.0

func (a *HttpAsset) GetSize() int

type HttpConfig added in v1.4.0

type HttpConfig struct {
	// BaseURL is a base URL of your update server. This parameter has NO default value.
	BaseURL string
	// HTTP Transport Config
	Transport *http.Transport
	// Additional headers
	Headers http.Header
}

HttpConfig is an object to pass to NewHttpSource

type HttpManifest added in v1.4.0

type HttpManifest struct {
	LastReleaseID int64          `yaml:"last_release_id"`
	LastAssetID   int64          `yaml:"last_asset_id"`
	Releases      []*HttpRelease `yaml:"releases"`
}

type HttpRelease added in v1.4.0

type HttpRelease struct {
	ID           int64        `yaml:"id"`
	Name         string       `yaml:"name"`
	TagName      string       `yaml:"tag_name"`
	URL          string       `yaml:"url"`
	Draft        bool         `yaml:"draft"`
	Prerelease   bool         `yaml:"prerelease"`
	PublishedAt  time.Time    `yaml:"published_at"`
	ReleaseNotes string       `yaml:"release_notes"`
	Assets       []*HttpAsset `yaml:"assets"`
}

func (*HttpRelease) GetAssets added in v1.4.0

func (r *HttpRelease) GetAssets() []SourceAsset

func (*HttpRelease) GetDraft added in v1.4.0

func (r *HttpRelease) GetDraft() bool

func (*HttpRelease) GetID added in v1.4.0

func (r *HttpRelease) GetID() int64

func (*HttpRelease) GetName added in v1.4.0

func (r *HttpRelease) GetName() string

func (*HttpRelease) GetPrerelease added in v1.4.0

func (r *HttpRelease) GetPrerelease() bool

func (*HttpRelease) GetPublishedAt added in v1.4.0

func (r *HttpRelease) GetPublishedAt() time.Time

func (*HttpRelease) GetReleaseNotes added in v1.4.0

func (r *HttpRelease) GetReleaseNotes() string

func (*HttpRelease) GetTagName added in v1.4.0

func (r *HttpRelease) GetTagName() string

func (*HttpRelease) GetURL added in v1.4.0

func (r *HttpRelease) GetURL() string

type HttpSource added in v1.4.0

type HttpSource struct {
	// contains filtered or unexported fields
}

HttpSource is used to load release information from an http repository

func NewHttpSource added in v1.4.0

func NewHttpSource(config HttpConfig) (*HttpSource, error)

NewHttpSource creates a new HttpSource from a config object.

func (*HttpSource) DownloadReleaseAsset added in v1.4.0

func (s *HttpSource) DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error)

DownloadReleaseAsset downloads an asset from a release. It returns an io.ReadCloser: it is your responsibility to Close it.

func (*HttpSource) ListReleases added in v1.4.0

func (s *HttpSource) ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error)

ListReleases returns all available releases

type Logger

type Logger interface {
	// Print calls Output to print to the standard logger. Arguments are handled in the manner of fmt.Print.
	Print(v ...interface{})
	// Printf calls Output to print to the standard logger. Arguments are handled in the manner of fmt.Printf.
	Printf(format string, v ...interface{})
}

Logger interface. Compatible with standard log.Logger

type PGPValidator added in v1.0.0

type PGPValidator struct {
	// KeyRing is usually filled by openpgp.ReadArmoredKeyRing(bytes.NewReader(key)) with key being the PGP pub key.
	KeyRing openpgp.EntityList
	// Binary toggles whether to validate detached *.sig (binary) or *.asc (ascii) signature files
	Binary bool
}

PGPValidator specifies a PGP validator for additional file validation before updating.

func (*PGPValidator) GetValidationAssetName added in v1.0.0

func (g *PGPValidator) GetValidationAssetName(releaseFilename string) string

GetValidationAssetName returns the asset name for PGP validation.

func (*PGPValidator) Validate added in v1.0.0

func (g *PGPValidator) Validate(filename string, release, signature []byte) (err error)

Validate checks the PGP signature of the release against the signature contained in an additional asset file.

func (*PGPValidator) WithArmoredKeyRing added in v1.0.0

func (g *PGPValidator) WithArmoredKeyRing(key []byte) *PGPValidator

WithArmoredKeyRing is a convenience method to set KeyRing

type PatternValidator added in v1.0.0

type PatternValidator struct {
	// contains filtered or unexported fields
}

PatternValidator specifies a validator for additional file validation that redirects to other validators depending on glob file patterns.

Unlike others, PatternValidator is a recursive validator that also checks validation assets (e.g. SHA256SUMS file checks assets and SHA256SUMS.asc checks the SHA256SUMS file). Depending on the used validators, a validation loop might be created, causing validation errors. In order to prevent this, use SkipValidation for validation assets that should not be checked (e.g. signature files). Note that glob pattern are matched in the order of addition. Add general patterns like "*" at last.

Usage Example (validate assets by SHA256SUMS and SHA256SUMS.asc):

 new(PatternValidator).
	// "SHA256SUMS" file is checked by PGP signature (from "SHA256SUMS.asc")
	Add("SHA256SUMS", new(PGPValidator).WithArmoredKeyRing(key)).
	// "SHA256SUMS.asc" file is not checked (is the signature for "SHA256SUMS")
	SkipValidation("*.asc").
	// All other files are checked by the "SHA256SUMS" file
	Add("*", &ChecksumValidator{UniqueFilename:"SHA256SUMS"})

func (*PatternValidator) Add added in v1.0.0

func (m *PatternValidator) Add(glob string, validator Validator) *PatternValidator

Add maps a new validator to the given glob pattern.

func (*PatternValidator) GetValidationAssetName added in v1.0.0

func (m *PatternValidator) GetValidationAssetName(releaseFilename string) string

GetValidationAssetName returns the asset name for validation.

func (*PatternValidator) MustContinueValidation added in v1.0.0

func (m *PatternValidator) MustContinueValidation(filename string) bool

MustContinueValidation returns true if validation must continue on the specified filename

func (*PatternValidator) SkipValidation added in v1.0.0

func (m *PatternValidator) SkipValidation(glob string) *PatternValidator

SkipValidation skips validation for the given glob pattern.

func (*PatternValidator) Validate added in v1.0.0

func (m *PatternValidator) Validate(filename string, release, asset []byte) error

Validate delegates to the first matching Validator that was configured with Add. It fails with ErrValidatorNotFound if no matching validator is configured.

type RecursiveValidator added in v1.0.0

type RecursiveValidator interface {
	// MustContinueValidation returns true if validation must continue on the provided filename
	MustContinueValidation(filename string) bool
}

RecursiveValidator may be implemented by validators that can continue validation on validation assets (multistep validation).

type Release

type Release struct {
	// AssetURL is a URL to the uploaded file for the release
	AssetURL string
	// AssetSize represents the size of asset in bytes
	AssetByteSize int
	// AssetID is the ID of the asset on the source platform
	AssetID int64
	// ReleaseID is the ID of the release on the source platform
	ReleaseID int64
	// AssetName is the filename of the asset
	AssetName string
	// ValidationAssetID is the ID of additional validation asset on the source platform
	ValidationAssetID int64
	// ValidationAssetURL is the URL of additional validation asset on the source platform
	ValidationAssetURL string
	// ValidationChain is the list of validation assets being used (first record is ValidationAssetID).
	ValidationChain []struct {
		// ValidationAssetID is the ID of additional validation asset on the source platform
		ValidationAssetID int64
		// ValidationAssetURL is the filename of additional validation asset on the source platform
		ValidationAssetName string
		// ValidationAssetURL is the URL of additional validation asset on the source platform
		ValidationAssetURL string
	}
	// URL is a URL to release page for browsing
	URL string
	// ReleaseNotes is a release notes of the release
	ReleaseNotes string
	// Name represents a name of the release
	Name string
	// PublishedAt is the time when the release was published
	PublishedAt time.Time
	// OS this release is for
	OS string
	// Arch this release is for
	Arch string
	// Arm 32bits version (if any). Valid values are 0 (unknown), 5, 6 or 7
	Arm uint8
	// Prerelease is set to true for alpha, beta or release candidates
	Prerelease bool
	// contains filtered or unexported fields
}

Release represents a release asset for current OS and arch.

func DetectLatest

func DetectLatest(ctx context.Context, repository Repository) (*Release, bool, error)

DetectLatest detects the latest release from the repository. This function is a shortcut version of updater.DetectLatest with the DefaultUpdater.

func DetectVersion

func DetectVersion(ctx context.Context, repository Repository, version string) (*Release, bool, error)

DetectVersion detects the given release from the repository.

func UpdateCommand

func UpdateCommand(ctx context.Context, cmdPath string, current string, repository Repository) (*Release, error)

UpdateCommand updates a given command binary to the latest version. This function is a shortcut version of updater.UpdateCommand using a DefaultUpdater()

func UpdateSelf

func UpdateSelf(ctx context.Context, current string, repository Repository) (*Release, error)

UpdateSelf updates the running executable itself to the latest version. This function is a shortcut version of updater.UpdateSelf using a DefaultUpdater()

func (Release) Equal

func (r Release) Equal(other string) bool

Equal tests if two versions are equal to each other.

func (Release) GreaterOrEqual

func (r Release) GreaterOrEqual(other string) bool

GreaterOrEqual tests if one version is greater than or equal to another one.

func (Release) GreaterThan

func (r Release) GreaterThan(other string) bool

GreaterThan tests if one version is greater than another one.

func (Release) LessOrEqual

func (r Release) LessOrEqual(other string) bool

LessOrEqual tests if one version is less than or equal to another one.

func (Release) LessThan

func (r Release) LessThan(other string) bool

LessThan tests if one version is less than another one.

func (Release) Version

func (r Release) Version() string

Version is the version string of the release

type Repository added in v1.0.0

type Repository interface {
	GetSlug() (string, string, error)
	Get() (interface{}, error)
}

type RepositoryID added in v1.0.0

type RepositoryID int

func NewRepositoryID added in v1.0.0

func NewRepositoryID(id int) RepositoryID

NewRepositoryID creates a repository ID from an integer

func (RepositoryID) Get added in v1.0.0

func (r RepositoryID) Get() (interface{}, error)

func (RepositoryID) GetSlug added in v1.0.0

func (r RepositoryID) GetSlug() (string, string, error)

type RepositorySlug added in v1.0.0

type RepositorySlug struct {
	// contains filtered or unexported fields
}

func NewRepositorySlug added in v1.0.0

func NewRepositorySlug(owner, repo string) RepositorySlug

NewRepositorySlug creates a RepositorySlug from owner and repo parameters

func ParseSlug added in v1.0.0

func ParseSlug(slug string) RepositorySlug

ParseSlug is used to take a string "owner/repo" to make a RepositorySlug

func (RepositorySlug) Get added in v1.0.0

func (r RepositorySlug) Get() (interface{}, error)

func (RepositorySlug) GetSlug added in v1.0.0

func (r RepositorySlug) GetSlug() (string, string, error)

type SHAValidator

type SHAValidator struct {
}

SHAValidator specifies a SHA256 validator for additional file validation before updating.

func (*SHAValidator) GetValidationAssetName

func (v *SHAValidator) GetValidationAssetName(releaseFilename string) string

GetValidationAssetName returns the asset name for SHA256 validation.

func (*SHAValidator) Validate

func (v *SHAValidator) Validate(filename string, release, asset []byte) error

Validate checks the SHA256 sum of the release against the contents of an additional asset file.

type Source

type Source interface {
	ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error)
	DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error)
}

Source interface to load the releases from (GitHubSource for example)

type SourceAsset

type SourceAsset interface {
	GetID() int64
	GetName() string
	GetSize() int
	GetBrowserDownloadURL() string
}

type SourceRelease

type SourceRelease interface {
	GetID() int64
	GetTagName() string
	GetDraft() bool
	GetPrerelease() bool
	GetPublishedAt() time.Time
	GetReleaseNotes() string
	GetName() string
	GetURL() string

	GetAssets() []SourceAsset
}

type Updater

type Updater struct {
	// contains filtered or unexported fields
}

Updater is responsible for managing the context of self-update.

func DefaultUpdater

func DefaultUpdater() *Updater

DefaultUpdater creates a new updater instance with default configuration. It initializes GitHub API client with default API base URL. If you set your API token to $GITHUB_TOKEN, the client will use it. Every call to this function will always return the same instance, it's only created once

func NewUpdater

func NewUpdater(config Config) (*Updater, error)

NewUpdater creates a new updater instance. If you don't specify a source in the config object, GitHub will be used

func (*Updater) DetectLatest

func (up *Updater) DetectLatest(ctx context.Context, repository Repository) (release *Release, found bool, err error)

DetectLatest tries to get the latest version from the source provider. It fetches releases information from the source provider and find out the latest release with matching the tag names and asset names. Drafts and pre-releases are ignored. Assets would be suffixed by the OS name and the arch name such as 'foo_linux_amd64' where 'foo' is a command name. '-' can also be used as a separator. File can be compressed with zip, gzip, xz, bzip2, tar&gzip or tar&xz. So the asset can have a file extension for the corresponding compression format such as '.zip'. On Windows, '.exe' also can be contained such as 'foo_windows_amd64.exe.zip'.

func (*Updater) DetectVersion

func (up *Updater) DetectVersion(ctx context.Context, repository Repository, version string) (release *Release, found bool, err error)

DetectVersion tries to get the given version from the source provider. And version indicates the required version.

func (*Updater) UpdateCommand

func (up *Updater) UpdateCommand(ctx context.Context, cmdPath string, current string, repository Repository) (*Release, error)

UpdateCommand updates a given command binary to the latest version. 'current' is used to check the latest version against the current version.

func (*Updater) UpdateSelf

func (up *Updater) UpdateSelf(ctx context.Context, current string, repository Repository) (*Release, error)

UpdateSelf updates the running executable itself to the latest version. 'current' is used to check the latest version against the current version.

func (*Updater) UpdateTo

func (up *Updater) UpdateTo(ctx context.Context, rel *Release, cmdPath string) error

UpdateTo downloads an executable from the source provider and replace current binary with the downloaded one. It downloads a release asset via the source provider so this function is available for update releases on private repository.

type Validator

type Validator interface {
	// Validate validates release bytes against an additional asset bytes.
	// See SHAValidator or ECDSAValidator for more information.
	Validate(filename string, release, asset []byte) error
	// GetValidationAssetName returns the additional asset name containing the validation checksum.
	// The asset containing the checksum can be based on the release asset name
	// Please note if the validation file cannot be found, the DetectLatest and DetectVersion methods
	// will fail with a wrapped ErrValidationAssetNotFound error
	GetValidationAssetName(releaseFilename string) string
}

Validator represents an interface which enables additional validation of releases.

func NewChecksumWithECDSAValidator added in v1.0.0

func NewChecksumWithECDSAValidator(checksumsFilename string, pemECDSACertificate []byte) Validator

NewChecksumWithECDSAValidator returns a validator that checks assets with a checksums file (e.g. SHA256SUMS) and the checksums file with an ECDSA signature (e.g. SHA256SUMS.sig).

func NewChecksumWithPGPValidator added in v1.0.0

func NewChecksumWithPGPValidator(checksumsFilename string, armoredPGPKeyRing []byte) Validator

NewChecksumWithPGPValidator returns a validator that checks assets with a checksums file (e.g. SHA256SUMS) and the checksums file with an armored PGP signature (e.g. SHA256SUMS.asc).

Directories

Path Synopsis
cmd
serve-repo
Simple implementation of a HTTP server to be used by the updater with the http source
Simple implementation of a HTTP server to be used by the updater with the http source
Package update provides functionality to implement secure, self-updating Go programs (or other single-file targets).
Package update provides functionality to implement secure, self-updating Go programs (or other single-file targets).

Jump to

Keyboard shortcuts

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