updater

package module
v3.0.6 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2024 License: MIT Imports: 19 Imported by: 2

README

updater-go

Library that helps verifying/updating go binary with new version

Usage example

package main

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/hellofresh/updater-go/v3"
	log "github.com/sirupsen/logrus"
)

const (
	githubOwner = "hellofresh"
	githubRepo  = "github-cli"
)

func main() {
	var (
		updateToVersion string
		ghToken         string
	)
	flag.StringVar(&updateToVersion, "version", "", "update to a particular version instead of the latest stable")
	flag.StringVar(&ghToken, "token", "", "GitHub token to use for Github access")

	flag.Parse()

	// Check to which version we need to update
	versionFilter := updater.StableRelease
	if updateToVersion != "" {
		versionFilter = func(name string, _ bool, _ bool) bool {
			return updateToVersion == name
		}
	}

	// Create release locator
	locator := updater.NewGithubClient(
		context.TODO(),
		githubOwner,
		githubRepo,
		ghToken,
		versionFilter,
		func(asset string) bool {
			return strings.Contains(asset, fmt.Sprintf("-%s-%s-", runtime.GOARCH, runtime.GOOS))
		},
		10 * time.Second,
	)

	// Find the release
	updateTo, err := locateRelease(locator, updateToVersion)
	if errors.Is(err, updater.ErrNoRepository) || errors.Is(err, updater.ErrUnauthorized) {
		log.WithError(err).Error("Unable to access the repository.\n  This is probably due to insufficient privileges of the access token.")
		os.Exit(1)
	}
	failOnError(err, "failed to retrieve the update release")

	// Use context with deadlines to specify different timeouts (optional)
	ctx, cancel := context.WithTimeout(context.TODO(), 30 * time.Second)
	defer cancel()

	// Fetch the release and update
	err = updater.SelfUpdate(ctx, updateTo)
	failOnError(err, "failed to update to version %s")

	fmt.Printf("Successfully updated to version %s!\n", updateTo.Name)
}

func failOnError(err error, message string) {
	if err != nil {
		log.WithError(err).Error(message)
		os.Exit(1)
	}
}

func locateRelease(locator updater.ReleaseLocator, version string) (updater.Release, error) {
	// No specific version use the latest
	if version == "" {
		return updater.LatestRelease(context.TODO(), locator)
	}

	// Find a specific release
	var release updater.Release
	updates, err := locator.ListReleases(context.TODO(), 1)
	if err != nil {
		return release, err
	}

	if len(updates) == 0 {
		return release, fmt.Errorf("unable to locate release %s", version)
	}

	if len(updates) > 1 {
		return release, fmt.Errorf("multiple releases locate for %s", version)
	}

	return updates[0], nil
}

GitHub @hellofresh  ·  Medium @engineering.hellofresh

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoRepository error is returned if the repository is not found or user token has no access to it
	ErrNoRepository = errors.New("no repository")
	// ErrUnauthorized error is returned if user token does not have access to the repository or the token is invalid
	ErrUnauthorized = errors.New("no access to the repository, probably bad credentials")
)

Functions

func Apply

func Apply(update io.Reader, targetPath string, targetMode os.FileMode) error

Apply performs an update of the current executable (or opts.TargetFile, if set) with the contents of the given io.Reader.

Apply performs the following actions to ensure a safe cross-platform update:

  • Creates a new file, /path/to/.target.new with the TargetMode with the contents of the updated file
  • Renames /path/to/target to /path/to/.target.old
  • Renames /path/to/.target.new to /path/to/target
  • If the final rename is successful, deletes /path/to/.target.old, returns no error. On Windows, the removal of /path/to/target.old always fails, so instead Apply hides the old file instead.
  • If the final rename fails, attempts to roll back by renaming /path/to/.target.old back to /path/to/target.

If the rollback operation fails, the file system is left in an inconsistent state where there is no new executable file and the old executable file could not be be moved to its original location. In this case you should notify the user of the bad news and ask them to recover manually. Applications can determine whether the rollback failed by calling RollbackError, see the documentation on that function for additional detail.

func RegisterFormat

func RegisterFormat(name string, extractor Extractor)

RegisterFormat adds a supported archive format

func SelfUpdate

func SelfUpdate(ctx context.Context, release Release) error

SelfUpdate update the current executable to the release

func StableRelease

func StableRelease(_ string, draft bool, preRelease bool) bool

StableRelease filters out any release that is a draft or pre-release

Types

type AssetFilter

type AssetFilter func(asset string) bool

AssetFilter is a function that will filter out unsupported assets for the current system

type BinaryFilter

type BinaryFilter func(path os.FileInfo) bool

BinaryFilter is a function used to check if a given path/file is the binary needed

type Extractor

type Extractor interface {
	// Match checks supported files
	Match(filename string) bool
	// FetchBinary reads an archive and find return the reader for the binary based on the filter
	FetchBinary(input io.Reader, isBinary BinaryFilter) (io.Reader, error)
}

Extractor represent a archive extractor

func MatchingExtractor

func MatchingExtractor(path string) Extractor

MatchingExtractor returns the first extractor that matches the given file, or nil if there is no match

type GitHubLocatorOption added in v3.0.2

type GitHubLocatorOption interface {
	// contains filtered or unexported methods
}

GitHubLocatorOption is an option to configure GithubLocator.

func WithTracerProvider added in v3.0.2

func WithTracerProvider(tp trace.TracerProvider) GitHubLocatorOption

WithTracerProvider sets the TracerProvider.

type GithubLocator

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

GithubLocator struct encapsulates information about github repo

func NewGithubClient

func NewGithubClient(
	ctx context.Context,
	owner string,
	repository string,
	token string,
	releaseFilter ReleaseFilter,
	assetFilter AssetFilter,
	connectionTimeout time.Duration,
	opts ...GitHubLocatorOption,
) *GithubLocator

NewGithubClient creates new github locator instance

func (*GithubLocator) ListReleases

func (g *GithubLocator) ListReleases(ctx context.Context, amount int) (_ []Release, err error)

ListReleases returns available GH releases list.

type HTTPDownloader

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

HTTPDownloader represents http downloader client

func NewHTTPDownloader

func NewHTTPDownloader(client *http.Client) *HTTPDownloader

NewHTTPDownloader creates new http downloader client instance. If the passed client is nil http.DefaultClient is used.

func (*HTTPDownloader) Fetch

func (d *HTTPDownloader) Fetch(ctx context.Context, r Release) (io.ReadCloser, error)

Fetch downloads GH release

type Release

type Release struct {
	// Name the name of the release. In most cases this will be the version number
	Name string
	// Assert the name of the asset related to the URL
	Asset string
	// URL the download location of the Asset
	URL string
}

Release contains information about a release for the current system

func LatestRelease

func LatestRelease(ctx context.Context, locator ReleaseLocator) (Release, error)

LatestRelease retrieve the latest release from the locator using semver

func SelfUpdateToLatest

func SelfUpdateToLatest(ctx context.Context, locator ReleaseLocator) (Release, error)

SelfUpdateToLatest update the current executable to it's latest version

type ReleaseDownloader

type ReleaseDownloader interface {
	// Fetch downloads the release
	Fetch(ctx context.Context, r Release) (io.ReadCloser, error)
}

ReleaseDownloader describes a way to download/load a release

var (
	// ErrNoRelease error is returned in case no available releases were found.
	ErrNoRelease = errors.New("no releases were found")

	// DefaultDownloader the default downloaded to use.
	DefaultDownloader ReleaseDownloader
)

type ReleaseFilter

type ReleaseFilter func(name string, draft bool, preRelease bool) bool

ReleaseFilter is a function that will filter out releases. This is very useful when you want to support stable, beta and dev channels.

type ReleaseLocator

type ReleaseLocator interface {
	ListReleases(ctx context.Context, amount int) ([]Release, error)
}

ReleaseLocator describing a release locator that will fetch releases. A release locator should use the ReleaseFilter and AssetFilter during initialization.

type RollbackErr

type RollbackErr struct {

	// RollbackErr the error encountered while rolling back.
	RollbackErr error
	// contains filtered or unexported fields
}

RollbackErr represents an error occurred during rollback operation.

Jump to

Keyboard shortcuts

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