Skip to content

Commit

Permalink
Fix update not properly decompress content (#52)
Browse files Browse the repository at this point in the history
* Fix update not properly decompress content

* Fix unit test
  • Loading branch information
XiaoConstantine authored Jul 16, 2024
1 parent 06a6c82 commit 1819069
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 11 deletions.
64 changes: 55 additions & 9 deletions pkg/commands/update/update.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package update

import (
"archive/tar"
"compress/gzip"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -108,7 +110,7 @@ func updateCLI(iostream *iostreams.IOStreams) error {
installPath := filepath.Join(installDir, "mycli")

// Create a temporary file
tmpFile, err := os.CreateTemp("", "mycli-update")
tmpFile, err := os.CreateTemp("", "mycli-update-*.tar.gz")
if err != nil {
return fmt.Errorf("failed to create temporary file: %w", err)
}
Expand All @@ -121,18 +123,62 @@ func updateCLI(iostream *iostreams.IOStreams) error {
}
tmpFile.Close()

// Make the temporary file executable
if err := os.Chmod(tmpFile.Name(), 0755); err != nil {
return fmt.Errorf("failed to make new binary executable: %w", err)
// Open the temporary file for reading
tmpFile, err = os.Open(tmpFile.Name())
if err != nil {
return fmt.Errorf("failed to open temporary file: %w", err)
}
defer tmpFile.Close()

// Replace the old binary with the new one
if err := os.Rename(tmpFile.Name(), installPath); err != nil {
return fmt.Errorf("failed to replace old binary: %w", err)
// Create a gzip reader
gzr, err := gzip.NewReader(tmpFile)
if err != nil {
return fmt.Errorf("failed to create gzip reader: %w", err)
}
defer gzr.Close()

fmt.Fprintf(iostream.Out, "mycli has been updated successfully to version %s!\n", release.TagName)
return nil
// Create a tar reader
tr := tar.NewReader(gzr)

// Extract the mycli binary
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return fmt.Errorf("failed to read tar: %w", err)
}

if header.Name == "mycli" {
// Create a new temporary file for the extracted binary
extractedTmp, err := os.CreateTemp("", "mycli-extracted")
if err != nil {
return fmt.Errorf("failed to create temporary file for extracted binary: %w", err)
}
defer os.Remove(extractedTmp.Name())

// Copy the file contents
if _, err := io.Copy(extractedTmp, tr); err != nil {
return fmt.Errorf("failed to extract binary: %w", err)
}
extractedTmp.Close()

// Make the temporary file executable
if err := os.Chmod(extractedTmp.Name(), 0755); err != nil {
return fmt.Errorf("failed to make new binary executable: %w", err)
}

// Replace the old binary with the new one
if err := os.Rename(extractedTmp.Name(), installPath); err != nil {
return fmt.Errorf("failed to replace old binary: %w", err)
}

fmt.Fprintf(iostream.Out, "mycli has been updated successfully to version %s!\n", release.TagName)
return nil
}
}
return fmt.Errorf("failed to find mycli binary in the downloaded archive")
}

var ensureInstallDirectory = func() (string, error) {
Expand Down
41 changes: 39 additions & 2 deletions pkg/commands/update/update_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package update

import (
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -74,11 +77,45 @@ func TestUpdateCLI(t *testing.T) {
err = os.WriteFile(mockBinaryPath, []byte("old binary"), 0755)
assert.NoError(t, err)

// Create a mock binary content
mockBinaryContent := []byte("new binary")

// Create a buffer to hold the tar.gz content
var buf bytes.Buffer

// Create a gzip writer
gw := gzip.NewWriter(&buf)

// Create a tar writer
tw := tar.NewWriter(gw)

// Add the mock binary to the tar archive
hdr := &tar.Header{
Name: "mycli",
Mode: 0755,
Size: int64(len(mockBinaryContent)),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if _, err := tw.Write(mockBinaryContent); err != nil {
t.Fatal(err)
}
// Close the tar writer
if err := tw.Close(); err != nil {
t.Fatal(err)
}

// Close the gzip writer
if err := gw.Close(); err != nil {
t.Fatal(err)
}

// Mock server
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Type", "application/gzip")
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte("new binary")); err != nil {
if _, err := w.Write(buf.Bytes()); err != nil {
return
}
}))
Expand Down

0 comments on commit 1819069

Please sign in to comment.