Back to Examples
Self-Updating CLI Tool
Build a command-line tool that can update itself automatically with version checking.
85 min
Advanced
GoRustPython
Overview
In this example, we'll create a command-line tool that can check for updates and replace itself with a new version when available. This is particularly useful for distributing tools that need to stay up-to-date.
Key Features
- Version checking against a remote repository
- Secure binary verification
- Atomic updates to prevent corruption
- Cross-platform compatibility
- Clean rollback on failed updates
Implementation Steps
- Version Checking
Implement a function to check the current version against a remote version endpoint.
- Download New Version
Securely download the new binary to a temporary location.
- Verification
Verify the downloaded binary's checksum and signature.
- Atomic Replacement
Replace the current binary with the new version in an atomic operation.
- Restart
Restart the application with the new version if needed.
Example Code (Go)
package main
import (
"crypto/sha256"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
)
func checkForUpdate(currentVersion string) (bool, string, error) {
// Implementation would check a remote endpoint
// and return if an update is available with the new version
return false, "", nil
}
func downloadUpdate(version string) (string, error) {
// Implementation would download the new binary
return "", nil
}
func verifyChecksum(filePath, expectedChecksum string) bool {
// Implementation would verify the file's checksum
return true
}
func replaceBinary(newBinaryPath string) error {
// Implementation would replace the current binary
return nil
}
func main() {
currentVersion := "1.0.0"
updateAvailable, newVersion, err := checkForUpdate(currentVersion)
if err != nil {
fmt.Printf("Error checking for updates: %v
", err)
return
}
if updateAvailable {
fmt.Printf("Updating to version %s...
", newVersion)
// Download and verify new version
tempPath, err := downloadUpdate(newVersion)
if err != nil {
fmt.Printf("Error downloading update: %v
", err)
return
}
// Replace current binary
if err := replaceBinary(tempPath); err != nil {
fmt.Printf("Error applying update: %v
", err)
return
}
fmt.Println("Update completed successfully!")
} else {
fmt.Println("Already up to date!")
}
}
Concepts Covered
Auto-UpdatesVersion ManagementBinary Distribution