Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use callback for printing update progress #1799

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/action/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func (s *Action) Update(c *cli.Context) error {
return fmt.Errorf("gopass update is not supported on windows (#1722)")
}

out.Printf(ctx, "⚒ Checking for available updates ...")
if err := updater.Update(ctx, s.version); err != nil {
out.Print(ctx, "⚒ Checking for available updates ...")
if err := updater.Update(ctx, s.version, out.Printf); err != nil {
return ExitError(ExitUnknown, err, "Failed to update gopass: %s", err)
}
out.OKf(ctx, "gopass is up to date")
Expand Down
32 changes: 16 additions & 16 deletions internal/updater/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/gopasspw/gopass/pkg/debug"
)

func extractFile(buf []byte, filename, dest string) error {
func extractFile(buf []byte, filename, dest string) (int64, error) {
var mode = os.FileMode(0755)

// if overwriting an existing binary retain it's mode flags
Expand All @@ -25,13 +25,13 @@ func extractFile(buf []byte, filename, dest string) error {

if err := os.Remove(dest); err != nil {
if !os.IsNotExist(err) {
return fmt.Errorf("unable to remove destination file: %q", err)
return 0, fmt.Errorf("unable to remove destination file: %q", err)
}
}

dfh, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_EXCL, mode)
if err != nil {
return fmt.Errorf("failed to open file %q: %w", dest, err)
return 0, fmt.Errorf("failed to open file %q: %w", dest, err)
}
defer func() {
_ = dfh.Close()
Expand All @@ -42,22 +42,22 @@ func extractFile(buf []byte, filename, dest string) error {
case ".gz":
gzr, err := gzip.NewReader(rd)
if err != nil {
return err
return 0, err
}
return extractTar(gzr, dfh, dest)
case ".bz2":
return extractTar(bzip2.NewReader(rd), dfh, dest)
case ".zip":
return extractZip(buf, dfh, dest)
default:
return fmt.Errorf("unsupported")
return 0, fmt.Errorf("unsupported")
}
}

func extractZip(buf []byte, dfh io.WriteCloser, dest string) error {
func extractZip(buf []byte, dfh io.WriteCloser, dest string) (int64, error) {
zrd, err := zip.NewReader(bytes.NewReader(buf), int64(len(buf)))
if err != nil {
return err
return 0, err
}

for i := 0; i < len(zrd.File); i++ {
Expand All @@ -67,32 +67,32 @@ func extractZip(buf []byte, dfh io.WriteCloser, dest string) error {

file, err := zrd.File[i].Open()
if err != nil {
return fmt.Errorf("failed to read from zip file: %w", err)
return 0, fmt.Errorf("failed to read from zip file: %w", err)
}

n, err := io.Copy(dfh, file)
if err != nil {
dfh.Close()
os.Remove(dest)
return fmt.Errorf("failed to read gopass.exe from zip file: %w", err)
return 0, fmt.Errorf("failed to read gopass.exe from zip file: %w", err)
}
// success
debug.Log("wrote %d bytes to %v", n, dest)
return nil
return n, nil
}

return fmt.Errorf("file not found in archive")
return 0, fmt.Errorf("file not found in archive")
}

func extractTar(rd io.Reader, dfh io.WriteCloser, dest string) error {
func extractTar(rd io.Reader, dfh io.WriteCloser, dest string) (int64, error) {
tarReader := tar.NewReader(rd)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
return fmt.Errorf("failed to read from tar file: %w", err)
return 0, fmt.Errorf("failed to read from tar file: %w", err)
}
name := filepath.Base(header.Name)
if header.Typeflag != tar.TypeReg {
Expand All @@ -106,11 +106,11 @@ func extractTar(rd io.Reader, dfh io.WriteCloser, dest string) error {
if err != nil {
dfh.Close()
os.Remove(dest)
return fmt.Errorf("failed to read gopass from tar file: %w", err)
return n, fmt.Errorf("failed to read gopass from tar file: %w", err)
}
// success
debug.Log("wrote %d bytes to %v", n, dest)
return nil
return n, nil
}
return fmt.Errorf("file not found in archive")
return 0, fmt.Errorf("file not found in archive")
}
34 changes: 24 additions & 10 deletions internal/updater/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@ var (
UpdateMoveAfterQuit = true
)

// PrintCallback is a method that can print formatted text, e.g. out.Print
type PrintCallback func(context.Context, string, ...interface{})

// Update will start th interactive update assistant
func Update(ctx context.Context, currentVersion semver.Version) error {
func Update(ctx context.Context, currentVersion semver.Version, printf PrintCallback) error {
if printf == nil {
printf = func(ctx context.Context, fmt string, args ...interface{}) {
// no-op
}
}

if err := IsUpdateable(ctx); err != nil {
out.Errorf(ctx, "Your gopass binary is externally managed. Can not update: %q", err)
printf(ctx, "Your gopass binary is externally managed. Can not update: %q", err)
return err
}

Expand All @@ -39,19 +48,20 @@ func Update(ctx context.Context, currentVersion semver.Version) error {
debug.Log("Current: %s - Latest: %s", currentVersion.String(), rel.Version.String())
// binary is newer or equal to the latest release -> nothing to do
if currentVersion.GTE(rel.Version) {
out.Printf(ctx, "gopass is up to date (%s)", currentVersion.String())
printf(ctx, "gopass is up to date (%s)", currentVersion.String())
if gfu := os.Getenv("GOPASS_FORCE_UPDATE"); gfu == "" {
return nil
}
}

debug.Log("downloading SHA256SUMS ...")
printf(ctx, "latest version is %s", rel.Version.String())
printf(ctx, "downloading SHA256SUMS")
_, sha256sums, err := downloadAsset(ctx, rel.Assets, "SHA256SUMS")
if err != nil {
return err
}

debug.Log("downloading SHA256SUMS.sig ...")
out.Print(ctx, "downloading SHA256SUMS.sig")
_, sig, err := downloadAsset(ctx, rel.Assets, "SHA256SUMS.sig")
if err != nil {
return err
Expand All @@ -63,17 +73,17 @@ func Update(ctx context.Context, currentVersion semver.Version) error {
return fmt.Errorf("signature verification failed: %w", err)
}
if !ok {
return fmt.Errorf("GPG signature verification for SHA256SUMS failed")
return fmt.Errorf("GPG signature verification failed")
}
debug.Log("GPG signature OK!")
printf(ctx, "GPG signature verification succeeded")

ext := "tar.gz"
if runtime.GOOS == "windows" {
ext = "zip"
}

suffix := fmt.Sprintf("%s-%s.%s", runtime.GOOS, runtime.GOARCH, ext)
debug.Log("downloading tarball %q ...", suffix)
printf(ctx, "downloading gopass-%s", suffix)
dlFilename, buf, err := downloadAsset(ctx, rel.Assets, suffix)
if err != nil {
return err
Expand All @@ -90,14 +100,18 @@ func Update(ctx context.Context, currentVersion semver.Version) error {
if !bytes.Equal(wantHash, gotHash[:]) {
return fmt.Errorf("SHA256 hash mismatch, want %02x, got %02x", wantHash, gotHash)
}

debug.Log("hashsums match!")
printf(ctx, "downloaded gopass-%s", suffix)

debug.Log("extracting binary from tarball ...")
if err := extractFile(buf, dlFilename, dest); err != nil {
size, err := extractFile(buf, dlFilename, dest)
if err != nil {
return err
}
debug.Log("extracted %q to %q", dlFilename, dest)

debug.Log("success!")
printf(ctx, "saved %d bytes to %s", size, dest)
printf(ctx, "successfully updated gopass to version %s", rel.Version.String())
return nil
}