From 4fdc52e7602f8daed5fdfa7794f20182195b58a4 Mon Sep 17 00:00:00 2001
From: QuintenQVD0 <josdekurk@gmail.com>
Date: Mon, 2 Dec 2024 17:53:10 +0100
Subject: [PATCH 1/7] add selfupdate

---
 cmd/root.go       |  23 +++--
 cmd/selfupdate.go | 257 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 269 insertions(+), 11 deletions(-)
 create mode 100644 cmd/selfupdate.go

diff --git a/cmd/root.go b/cmd/root.go
index 258858f..2a67dd6 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -88,23 +88,24 @@ func init() {
 	rootCommand.AddCommand(versionCommand)
 	rootCommand.AddCommand(configureCmd)
 	rootCommand.AddCommand(newDiagnosticsCommand())
+	rootCommand.AddCommand(newSelfupdateCommand())
 }
 
 func isDockerSnap() bool {
-    cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
-    if err != nil {
-        log.Fatalf("Unable to initialize Docker client: %s", err)
-    }
+	cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
+	if err != nil {
+		log.Fatalf("Unable to initialize Docker client: %s", err)
+	}
 
-    defer cli.Close() // Close the client when the function returns (should not be needed, but just to be safe)
+	defer cli.Close() // Close the client when the function returns (should not be needed, but just to be safe)
 
-    info, err := cli.Info(context.Background())
-    if err != nil {
-        log.Fatalf("Unable to get Docker info: %s", err)
-    }
+	info, err := cli.Info(context.Background())
+	if err != nil {
+		log.Fatalf("Unable to get Docker info: %s", err)
+	}
 
-    // Check if Docker root directory contains '/var/snap/docker'
-    return strings.Contains(info.DockerRootDir, "/var/snap/docker")
+	// Check if Docker root directory contains '/var/snap/docker'
+	return strings.Contains(info.DockerRootDir, "/var/snap/docker")
 }
 
 func rootCmdRun(cmd *cobra.Command, _ []string) {
diff --git a/cmd/selfupdate.go b/cmd/selfupdate.go
new file mode 100644
index 0000000..498d753
--- /dev/null
+++ b/cmd/selfupdate.go
@@ -0,0 +1,257 @@
+package cmd
+
+import (
+	"crypto/sha256"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"os/exec"
+	"runtime"
+	"strings"
+	"time"
+
+	"github.com/pelican-dev/wings/system"
+	"github.com/spf13/cobra"
+)
+
+var updateArgs struct {
+	repoOwner string
+	repoName  string
+}
+
+func newSelfupdateCommand() *cobra.Command {
+	command := &cobra.Command{
+		Use:   "update",
+		Short: "Update the wings to the latest version",
+		Run:   selfupdateCmdRun,
+	}
+
+	command.Flags().StringVar(&updateArgs.repoOwner, "repo-owner", "pelican-dev", "GitHub username or organization that owns the repository containing the updates")
+	command.Flags().StringVar(&updateArgs.repoName, "repo-name", "wings", "The name of the GitHub repository to fetch updates from")
+
+	return command
+}
+
+func selfupdateCmdRun(*cobra.Command, []string) {
+	currentVersion := system.Version
+	if currentVersion == "" {
+		fmt.Println("Error: Current version is not defined")
+		return
+	}
+
+	if currentVersion == "develop" {
+		fmt.Println("Running in development mode. Skipping update.")
+		return
+	}
+
+	fmt.Println("Current version:", currentVersion)
+
+	// Fetch the latest release tag from GitHub API
+	latestVersionTag, err := fetchLatestGitHubRelease()
+	if err != nil {
+		fmt.Println("Failed to fetch the latest version:", err)
+		return
+	}
+
+	currentVersionTag := "v" + currentVersion
+	if latestVersionTag == currentVersionTag {
+		fmt.Println("You are running the latest version:", currentVersion)
+		return
+	}
+
+	fmt.Printf("A new version is available: %s (current: %s)\n", latestVersionTag, currentVersionTag)
+
+	binaryName := determineBinaryName()
+	if binaryName == "" {
+		fmt.Println("Unsupported architecture")
+		return
+	}
+
+	downloadURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s", updateArgs.repoOwner, updateArgs.repoName, latestVersionTag, binaryName)
+	checksumURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/checksums.txt", updateArgs.repoOwner, updateArgs.repoName, latestVersionTag)
+
+	fmt.Println("Downloading checksums.txt...")
+	checksumFile, err := downloadFile(checksumURL, "checksums.txt")
+	if err != nil {
+		fmt.Println("Failed to download checksum file:", err)
+		return
+	}
+	defer os.Remove(checksumFile)
+
+	fmt.Println("Downloading", binaryName, "...")
+	binaryFile, err := downloadFile(downloadURL, binaryName)
+	if err != nil {
+		fmt.Println("Failed to download binary file:", err)
+		return
+	}
+	defer os.Remove(binaryFile)
+
+	if err := verifyChecksum(binaryFile, checksumFile, binaryName); err != nil {
+		fmt.Println("Checksum verification failed:", err)
+		return
+	}
+	fmt.Println("\nChecksum verification successful.")
+
+	currentExecutable, err := os.Executable()
+	if err != nil {
+		fmt.Println("Failed to locate current executable:", err)
+		return
+	}
+
+	if err := os.Chmod(binaryFile, 0755); err != nil {
+		fmt.Println("Failed to set executable permissions on the new binary:", err)
+		return
+	}
+
+	if err := replaceBinary(currentExecutable, binaryFile); err != nil {
+		fmt.Println("Failed to replace executable:", err)
+		return
+	}
+
+	fmt.Println("Restarting service...")
+
+	if err := restartService(); err != nil {
+		fmt.Println("Error restarting the wings service:", err)
+	} else {
+		fmt.Println("Service restarted successfully.")
+	}
+}
+
+func fetchLatestGitHubRelease() (string, error) {
+	apiURL := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", updateArgs.repoOwner, updateArgs.repoName)
+
+	resp, err := http.Get(apiURL)
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode)
+	}
+
+	var releaseData struct {
+		TagName string `json:"tag_name"`
+	}
+	if err := json.NewDecoder(resp.Body).Decode(&releaseData); err != nil {
+		return "", err
+	}
+
+	return releaseData.TagName, nil
+}
+
+func determineBinaryName() string {
+	switch runtime.GOARCH {
+	case "amd64":
+		return "wings_linux_amd64"
+	case "arm64":
+		return "wings_linux_arm64"
+	default:
+		return ""
+	}
+}
+
+func downloadFile(url, fileName string) (string, error) {
+	tmpFile, err := os.CreateTemp("", fileName)
+	if err != nil {
+		return "", err
+	}
+	defer tmpFile.Close()
+
+	resp, err := http.Get(url)
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return "", fmt.Errorf("unexpected status: %s", resp.Status)
+	}
+
+	fmt.Printf("Downloading %s (%.2f MB)...\n", fileName, float64(resp.ContentLength)/1024/1024)
+	progressWriter := &progressWriter{Writer: tmpFile, Total: resp.ContentLength}
+	if _, err := io.Copy(progressWriter, resp.Body); err != nil {
+		return "", err
+	}
+
+	fmt.Println() // Ensure a newline after download progress
+	return tmpFile.Name(), nil
+}
+
+func verifyChecksum(binaryPath, checksumPath, binaryName string) error {
+	checksumData, err := os.ReadFile(checksumPath)
+	if err != nil {
+		return err
+	}
+
+	var expectedChecksum string
+	for _, line := range strings.Split(string(checksumData), "\n") {
+		if strings.HasSuffix(line, binaryName) {
+			parts := strings.Fields(line)
+			if len(parts) > 0 {
+				expectedChecksum = parts[0]
+			}
+			break
+		}
+	}
+	if expectedChecksum == "" {
+		return fmt.Errorf("checksum not found for %s", binaryName)
+	}
+
+	file, err := os.Open(binaryPath)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	hasher := sha256.New()
+	if _, err := io.Copy(hasher, file); err != nil {
+		return err
+	}
+	actualChecksum := fmt.Sprintf("%x", hasher.Sum(nil))
+
+	if actualChecksum != expectedChecksum {
+		return fmt.Errorf("checksum mismatch: expected %s, got %s", expectedChecksum, actualChecksum)
+	}
+
+	return nil
+}
+
+func replaceBinary(currentPath, newPath string) error {
+	return os.Rename(newPath, currentPath)
+}
+
+type progressWriter struct {
+	io.Writer
+	Total     int64
+	Written   int64
+	StartTime time.Time
+}
+
+func (pw *progressWriter) Write(p []byte) (int, error) {
+	n, err := pw.Writer.Write(p)
+	pw.Written += int64(n)
+
+	if pw.Total > 0 {
+		percent := float64(pw.Written) / float64(pw.Total) * 100
+		fmt.Printf("\rProgress: %.2f%%", percent)
+	}
+
+	return n, err
+}
+
+func restartService() error {
+	// Try to run the systemctl restart command
+	cmd := exec.Command("systemctl", "restart", "wings")
+	cmdOutput, err := cmd.CombinedOutput()
+
+	if err != nil {
+		// If systemctl command fails, return the error with output
+		return fmt.Errorf("failed to restart service: %s\n%s", err.Error(), string(cmdOutput))
+	}
+
+	// If successful, return nil
+	return nil
+}

From b14696d49d30695dc0836450dda8c2e99f6d2be5 Mon Sep 17 00:00:00 2001
From: QuintenQVD0 <josdekurk@gmail.com>
Date: Mon, 2 Dec 2024 18:02:11 +0100
Subject: [PATCH 2/7] Bump golang 1.23 sub version

---
 .github/workflows/push.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml
index 8abca1b..7bb52aa 100644
--- a/.github/workflows/push.yaml
+++ b/.github/workflows/push.yaml
@@ -16,7 +16,7 @@ jobs:
       fail-fast: false
       matrix:
         os: [ubuntu-22.04]
-        go: ["1.22.7", "1.23.1"]
+        go: ["1.22.7", "1.23.3"]
         goos: [linux]
         goarch: [amd64, arm64]
 

From b7e1b53341d374945927e6f7234ea4b299ece3f2 Mon Sep 17 00:00:00 2001
From: Quinten <67589015+QuintenQVD0@users.noreply.github.com>
Date: Sat, 7 Dec 2024 13:40:53 +0100
Subject: [PATCH 3/7] Remove systemd restart from autoupdate

---
 cmd/selfupdate.go | 21 +--------------------
 1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/cmd/selfupdate.go b/cmd/selfupdate.go
index 498d753..fef969e 100644
--- a/cmd/selfupdate.go
+++ b/cmd/selfupdate.go
@@ -110,13 +110,8 @@ func selfupdateCmdRun(*cobra.Command, []string) {
 		return
 	}
 
-	fmt.Println("Restarting service...")
+	fmt.Println("Now restart the wings service. Example: systemctl restart wings")
 
-	if err := restartService(); err != nil {
-		fmt.Println("Error restarting the wings service:", err)
-	} else {
-		fmt.Println("Service restarted successfully.")
-	}
 }
 
 func fetchLatestGitHubRelease() (string, error) {
@@ -241,17 +236,3 @@ func (pw *progressWriter) Write(p []byte) (int, error) {
 
 	return n, err
 }
-
-func restartService() error {
-	// Try to run the systemctl restart command
-	cmd := exec.Command("systemctl", "restart", "wings")
-	cmdOutput, err := cmd.CombinedOutput()
-
-	if err != nil {
-		// If systemctl command fails, return the error with output
-		return fmt.Errorf("failed to restart service: %s\n%s", err.Error(), string(cmdOutput))
-	}
-
-	// If successful, return nil
-	return nil
-}

From 9f7745f2fc6e37c9bd68187299e347f2acb46def Mon Sep 17 00:00:00 2001
From: Quinten <67589015+QuintenQVD0@users.noreply.github.com>
Date: Sat, 7 Dec 2024 13:47:43 +0100
Subject: [PATCH 4/7] we don't need os exec anymore

---
 cmd/selfupdate.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/cmd/selfupdate.go b/cmd/selfupdate.go
index fef969e..75b4a91 100644
--- a/cmd/selfupdate.go
+++ b/cmd/selfupdate.go
@@ -7,7 +7,6 @@ import (
 	"io"
 	"net/http"
 	"os"
-	"os/exec"
 	"runtime"
 	"strings"
 	"time"

From 1d19608bc5fe0641948e67293a0be9e9b7a7e407 Mon Sep 17 00:00:00 2001
From: Quinten <67589015+QuintenQVD0@users.noreply.github.com>
Date: Sat, 21 Dec 2024 11:52:08 +0100
Subject: [PATCH 5/7] cleanup

---
 cmd/selfupdate.go | 156 +++++++++++++++++++++++++---------------------
 1 file changed, 85 insertions(+), 71 deletions(-)

diff --git a/cmd/selfupdate.go b/cmd/selfupdate.go
index 75b4a91..e0b83f6 100644
--- a/cmd/selfupdate.go
+++ b/cmd/selfupdate.go
@@ -7,6 +7,7 @@ import (
 	"io"
 	"net/http"
 	"os"
+	"path/filepath"
 	"runtime"
 	"strings"
 	"time"
@@ -18,99 +19,139 @@ import (
 var updateArgs struct {
 	repoOwner string
 	repoName  string
+	force     bool
 }
 
 func newSelfupdateCommand() *cobra.Command {
 	command := &cobra.Command{
 		Use:   "update",
-		Short: "Update the wings to the latest version",
+		Short: "Update wings to the latest version",
 		Run:   selfupdateCmdRun,
 	}
 
-	command.Flags().StringVar(&updateArgs.repoOwner, "repo-owner", "pelican-dev", "GitHub username or organization that owns the repository containing the updates")
-	command.Flags().StringVar(&updateArgs.repoName, "repo-name", "wings", "The name of the GitHub repository to fetch updates from")
+	command.Flags().StringVar(&updateArgs.repoOwner, "repo-owner", "pelican-dev", "GitHub repository owner")
+	command.Flags().StringVar(&updateArgs.repoName, "repo-name", "wings", "GitHub repository name")
+	command.Flags().BoolVar(&updateArgs.force, "force", false, "Force update even if on latest version")
 
 	return command
 }
 
-func selfupdateCmdRun(*cobra.Command, []string) {
+func selfupdateCmdRun(_ *cobra.Command, _ []string) {
 	currentVersion := system.Version
 	if currentVersion == "" {
-		fmt.Println("Error: Current version is not defined")
+		fmt.Println("Error: current version is not defined")
 		return
 	}
 
-	if currentVersion == "develop" {
-		fmt.Println("Running in development mode. Skipping update.")
+	if currentVersion == "develop" && !updateArgs.force {
+		fmt.Println("Running in development mode. Use --force to override.")
 		return
 	}
 
-	fmt.Println("Current version:", currentVersion)
+	fmt.Printf("Current version: %s\n", currentVersion)
 
 	// Fetch the latest release tag from GitHub API
 	latestVersionTag, err := fetchLatestGitHubRelease()
 	if err != nil {
-		fmt.Println("Failed to fetch the latest version:", err)
+		fmt.Printf("Failed to fetch latest version: %v\n", err)
 		return
 	}
 
-	currentVersionTag := "v" + currentVersion
-	if latestVersionTag == currentVersionTag {
-		fmt.Println("You are running the latest version:", currentVersion)
-		return
+	var currentVersionTag string
+	if currentVersion != "develop" {
+		currentVersionTag = "v" + currentVersion
+	} else {
+		currentVersionTag = "develop"
 	}
 
-	fmt.Printf("A new version is available: %s (current: %s)\n", latestVersionTag, currentVersionTag)
+	if latestVersionTag == currentVersionTag && !updateArgs.force {
+		fmt.Printf("You are running the latest version: %s\n", currentVersion)
+		return
+	}
 
 	binaryName := determineBinaryName()
 	if binaryName == "" {
-		fmt.Println("Unsupported architecture")
+		fmt.Printf("Error: unsupported architecture: %s\n", runtime.GOARCH)
 		return
 	}
 
-	downloadURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s", updateArgs.repoOwner, updateArgs.repoName, latestVersionTag, binaryName)
-	checksumURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/checksums.txt", updateArgs.repoOwner, updateArgs.repoName, latestVersionTag)
+	fmt.Printf("Updating from %s to %s\n", currentVersionTag, latestVersionTag)
 
-	fmt.Println("Downloading checksums.txt...")
-	checksumFile, err := downloadFile(checksumURL, "checksums.txt")
-	if err != nil {
-		fmt.Println("Failed to download checksum file:", err)
+	if err := performUpdate(latestVersionTag, binaryName); err != nil {
+		fmt.Printf("Update failed: %v\n", err)
 		return
 	}
-	defer os.Remove(checksumFile)
 
-	fmt.Println("Downloading", binaryName, "...")
-	binaryFile, err := downloadFile(downloadURL, binaryName)
+	fmt.Println("\nUpdate successful! Please restart the wings service (e.g., systemctl restart wings)")
+}
+
+func performUpdate(version, binaryName string) error {
+	downloadURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s",
+		updateArgs.repoOwner, updateArgs.repoName, version, binaryName)
+	checksumURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/checksums.txt",
+		updateArgs.repoOwner, updateArgs.repoName, version)
+
+	tmpDir, err := os.MkdirTemp("", "wings-update-*")
 	if err != nil {
-		fmt.Println("Failed to download binary file:", err)
-		return
+		return fmt.Errorf("failed to create temp directory: %v", err)
 	}
-	defer os.Remove(binaryFile)
+	defer os.RemoveAll(tmpDir)
 
-	if err := verifyChecksum(binaryFile, checksumFile, binaryName); err != nil {
-		fmt.Println("Checksum verification failed:", err)
-		return
+	checksumPath := filepath.Join(tmpDir, "checksums.txt")
+	if err := downloadWithProgress(checksumURL, checksumPath); err != nil {
+		return fmt.Errorf("failed to download checksums: %v", err)
+	}
+
+	binaryPath := filepath.Join(tmpDir, binaryName)
+	if err := downloadWithProgress(downloadURL, binaryPath); err != nil {
+		return fmt.Errorf("failed to download binary: %v", err)
+	}
+
+	if err := verifyChecksum(binaryPath, checksumPath, binaryName); err != nil {
+		return fmt.Errorf("checksum verification failed: %v", err)
+	}
+
+	if err := os.Chmod(binaryPath, 0755); err != nil {
+		return fmt.Errorf("failed to set executable permissions: %v", err)
 	}
-	fmt.Println("\nChecksum verification successful.")
 
 	currentExecutable, err := os.Executable()
 	if err != nil {
-		fmt.Println("Failed to locate current executable:", err)
-		return
+		return fmt.Errorf("failed to locate current executable: %v", err)
 	}
 
-	if err := os.Chmod(binaryFile, 0755); err != nil {
-		fmt.Println("Failed to set executable permissions on the new binary:", err)
-		return
+	return os.Rename(binaryPath, currentExecutable)
+}
+
+func downloadWithProgress(url, dest string) error {
+	resp, err := http.Get(url)
+	if err != nil {
+		return err
 	}
+	defer resp.Body.Close()
 
-	if err := replaceBinary(currentExecutable, binaryFile); err != nil {
-		fmt.Println("Failed to replace executable:", err)
-		return
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("unexpected status: %s", resp.Status)
 	}
 
-	fmt.Println("Now restart the wings service. Example: systemctl restart wings")
+	out, err := os.Create(dest)
+	if err != nil {
+		return err
+	}
+	defer out.Close()
+
+	filename := filepath.Base(dest)
+	fmt.Printf("Downloading %s (%.2f MB)...\n", filename, float64(resp.ContentLength)/1024/1024)
+
+	pw := &progressWriter{
+		Writer:    out,
+		Total:     resp.ContentLength,
+		StartTime: time.Now(),
+	}
 
+	_, err = io.Copy(pw, resp.Body)
+	fmt.Println()
+	return err
 }
 
 func fetchLatestGitHubRelease() (string, error) {
@@ -147,33 +188,6 @@ func determineBinaryName() string {
 	}
 }
 
-func downloadFile(url, fileName string) (string, error) {
-	tmpFile, err := os.CreateTemp("", fileName)
-	if err != nil {
-		return "", err
-	}
-	defer tmpFile.Close()
-
-	resp, err := http.Get(url)
-	if err != nil {
-		return "", err
-	}
-	defer resp.Body.Close()
-
-	if resp.StatusCode != http.StatusOK {
-		return "", fmt.Errorf("unexpected status: %s", resp.Status)
-	}
-
-	fmt.Printf("Downloading %s (%.2f MB)...\n", fileName, float64(resp.ContentLength)/1024/1024)
-	progressWriter := &progressWriter{Writer: tmpFile, Total: resp.ContentLength}
-	if _, err := io.Copy(progressWriter, resp.Body); err != nil {
-		return "", err
-	}
-
-	fmt.Println() // Ensure a newline after download progress
-	return tmpFile.Name(), nil
-}
-
 func verifyChecksum(binaryPath, checksumPath, binaryName string) error {
 	checksumData, err := os.ReadFile(checksumPath)
 	if err != nil {
@@ -206,6 +220,10 @@ func verifyChecksum(binaryPath, checksumPath, binaryName string) error {
 	}
 	actualChecksum := fmt.Sprintf("%x", hasher.Sum(nil))
 
+	if actualChecksum == expectedChecksum {
+		fmt.Printf("checksum matched!\n")
+	}
+
 	if actualChecksum != expectedChecksum {
 		return fmt.Errorf("checksum mismatch: expected %s, got %s", expectedChecksum, actualChecksum)
 	}
@@ -213,10 +231,6 @@ func verifyChecksum(binaryPath, checksumPath, binaryName string) error {
 	return nil
 }
 
-func replaceBinary(currentPath, newPath string) error {
-	return os.Rename(newPath, currentPath)
-}
-
 type progressWriter struct {
 	io.Writer
 	Total     int64

From 0aab589343320ee1d6198222c423c00898d34314 Mon Sep 17 00:00:00 2001
From: Quinten <67589015+QuintenQVD0@users.noreply.github.com>
Date: Fri, 27 Dec 2024 17:41:21 +0100
Subject: [PATCH 6/7] Simplify version logic

---
 cmd/selfupdate.go | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/cmd/selfupdate.go b/cmd/selfupdate.go
index e0b83f6..e058404 100644
--- a/cmd/selfupdate.go
+++ b/cmd/selfupdate.go
@@ -57,11 +57,9 @@ func selfupdateCmdRun(_ *cobra.Command, _ []string) {
 		return
 	}
 
-	var currentVersionTag string
-	if currentVersion != "develop" {
-		currentVersionTag = "v" + currentVersion
-	} else {
-		currentVersionTag = "develop"
+	currentVersionTag := "v" + currentVersion
+	if currentVersion == "develop" {
+		currentVersionTag = currentVersion
 	}
 
 	if latestVersionTag == currentVersionTag && !updateArgs.force {

From b8845f91c30c43a1aa375e9b7c2e57d622dcad68 Mon Sep 17 00:00:00 2001
From: Quinten <67589015+QuintenQVD0@users.noreply.github.com>
Date: Fri, 27 Dec 2024 17:51:57 +0100
Subject: [PATCH 7/7] Update: Checksum verification successful message

---
 cmd/selfupdate.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmd/selfupdate.go b/cmd/selfupdate.go
index e058404..aca23a2 100644
--- a/cmd/selfupdate.go
+++ b/cmd/selfupdate.go
@@ -219,7 +219,7 @@ func verifyChecksum(binaryPath, checksumPath, binaryName string) error {
 	actualChecksum := fmt.Sprintf("%x", hasher.Sum(nil))
 
 	if actualChecksum == expectedChecksum {
-		fmt.Printf("checksum matched!\n")
+		fmt.Printf("Checksum verification successful!\n")
 	}
 
 	if actualChecksum != expectedChecksum {