// Copyright © 2026 NAME HERE package cmd import ( "encoding/json" "fmt" "net/http" "os" "os/exec" "path/filepath" "strings" "time" "github.com/spf13/cobra" ) // updateCmd represents the update command var updateCmd = &cobra.Command{ Use: "update", Short: "Updates all AUR packages.", Long: `Just run apac update.`, Run: func(cmd *cobra.Command, args []string) { aurRPC := "https://aur.archlinux.org/rpc/v5/info?arg=" out, err := exec.Command("pacman", "-Qm").Output() if err != nil { fmt.Fprintln(os.Stderr, err) return } lines := strings.Split(strings.TrimSpace(string(out)), "\n") if len(lines) == 0 || (len(lines) == 1 && lines[0] == "") { fmt.Println("no aur packages found") return } var toUpdate []string for _, l := range lines { if l == "" { continue } pkg := strings.Fields(l)[0] // fetch AUR version aurV := "" { client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Get(aurRPC + pkg) if err == nil && resp != nil { var m map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&m); err == nil { if r, ok := m["results"].([]interface{}); ok && len(r) > 0 { if first, ok := r[0].(map[string]interface{}); ok { if v, ok := first["Version"].(string); ok { aurV = v } } } } resp.Body.Close() } } // local version localV := "" { out2, err := exec.Command("pacman", "-Qi", pkg).Output() if err == nil { for _, line := range strings.Split(string(out2), "\n") { if strings.HasPrefix(line, "Version") { parts := strings.SplitN(line, ":", 2) if len(parts) > 1 { localV = strings.TrimSpace(parts[1]) } break } } } } if aurV == "" { fmt.Printf("%s: not found in AUR\n", pkg) } else if aurV == localV { fmt.Printf("%s: up-to-date (%s)\n", pkg, aurV) } else if aurV > localV { fmt.Printf("%s: update available (AUR=%s local=%s)\n", pkg, aurV, localV) toUpdate = append(toUpdate, pkg) } else { fmt.Printf("%s: local newer (AUR=%s local=%s)\n", pkg, aurV, localV) } time.Sleep(150 * time.Millisecond) // small delay to be polite to AUR } if len(toUpdate) == 0 { fmt.Println("no updates found") return } // create a temporary work dir under current directory: ./apac-aur-builds- workDir := filepath.Join(".", fmt.Sprintf("apac-aur-builds-%d", time.Now().Unix())) if err := os.MkdirAll(workDir, 0o755); err != nil { fmt.Fprintln(os.Stderr, "failed to create work dir:", err) return } defer func() { // don't remove automatically — user might want to inspect builds fmt.Fprintln(os.Stderr, "builds kept in", workDir) }() // clone, makepkg -si for each package for _, p := range toUpdate { tarURL := fmt.Sprintf("https://aur.archlinux.org/%s.git", p) cloneDir := filepath.Join(workDir, p) fmt.Println("cloning", tarURL) cloneCmd := exec.Command("git", "clone", "--depth", "1", tarURL, cloneDir) cloneCmd.Stdin = os.Stdin cloneCmd.Stdout = os.Stdout cloneCmd.Stderr = os.Stderr if err := cloneCmd.Run(); err != nil { fmt.Fprintln(os.Stderr, "git clone failed for", p, ":", err) continue } // run makepkg -si in cloneDir fmt.Println("building", p) makeCmd := exec.Command("makepkg", "-si", "--noconfirm") makeCmd.Dir = cloneDir makeCmd.Stdin = os.Stdin makeCmd.Stdout = os.Stdout makeCmd.Stderr = os.Stderr if err := makeCmd.Run(); err != nil { fmt.Fprintln(os.Stderr, "makepkg failed for", p, ":", err) continue } } }, } func init() { rootCmd.AddCommand(updateCmd) }