package cmd import ( "fmt" "io" "os" "os/exec" "path/filepath" "time" "github.com/spf13/cobra" ) const cacheBase = "/var/cache/apac/pkgs" var installCmd = &cobra.Command{ Use: "install", Short: "installs a package", Long: `installs a package from the aur to the system.`, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { fmt.Fprintln(os.Stderr, "error: package name required") os.Exit(1) } pkg := args[0] url := "https://aur.archlinux.org/" + pkg // ensure cache directory exists (use sudo mkdir -p so permissions can be elevated) mkdirCmd := exec.Command("sudo", "mkdir", "-p", cacheBase) mkdirCmd.Stdin = os.Stdin mkdirCmd.Stdout = os.Stdout mkdirCmd.Stderr = os.Stderr if err := mkdirCmd.Run(); err != nil { fmt.Fprintf(os.Stderr, "failed to create cache dir %s: %v\n", cacheBase, err) os.Exit(1) } cacheDir := filepath.Join(cacheBase, pkg) tmpDir := filepath.Join(os.TempDir(), "apac-build-"+pkg+"-"+time.Now().Format("20060102-150405")) // clone into cache if missing; DO NOT pull/update existing cache if _, err := os.Stat(cacheDir); os.IsNotExist(err) { fmt.Println("cloning into cache:", url, "->", cacheDir) cloneCmd := exec.Command("sudo", "git", "clone", url, cacheDir) cloneCmd.Stdin = os.Stdin cloneCmd.Stdout = os.Stdout cloneCmd.Stderr = os.Stderr if err := cloneCmd.Run(); err != nil { fmt.Fprintf(os.Stderr, "git clone failed: %v\n", err) os.Exit(1) } } else if err != nil { fmt.Fprintf(os.Stderr, "stat cache dir failed: %v\n", err) os.Exit(1) } else { fmt.Println("using cached repo:", cacheDir) } // copy cached repo into a temporary build directory if err := copyDir(cacheDir, tmpDir); err != nil { fmt.Fprintf(os.Stderr, "failed to copy to build dir: %v\n", err) os.Exit(1) } defer os.RemoveAll(tmpDir) // run makepkg in tmpDir (makepkg will handle permissions) fmt.Println("building/installing:", pkg) buildCmd := exec.Command("makepkg", "-si", "--noconfirm") buildCmd.Dir = tmpDir buildCmd.Stdin = os.Stdin buildCmd.Stdout = os.Stdout buildCmd.Stderr = os.Stderr if err := buildCmd.Run(); err != nil { fmt.Fprintf(os.Stderr, "makepkg failed: %v\n", err) os.Exit(1) } fmt.Println("install successful") }, } func copyDir(src, dst string) error { if err := os.MkdirAll(dst, 0755); err != nil { return err } return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { if err != nil { return err } rel, err := filepath.Rel(src, path) if err != nil { return err } target := filepath.Join(dst, rel) if info.IsDir() { return os.MkdirAll(target, info.Mode()) } in, err := os.Open(path) if err != nil { return err } defer in.Close() out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, info.Mode()) if err != nil { return err } defer out.Close() _, err = io.Copy(out, in) return err }) } func init() { rootCmd.AddCommand(installCmd) }