344 lines
9.0 KiB
Go
344 lines
9.0 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/briandowns/spinner"
|
|
"upm/pkg_manager"
|
|
)
|
|
|
|
var (
|
|
// Color definitions
|
|
success = color.New(color.FgGreen, color.Bold)
|
|
errorColor = color.New(color.FgRed, color.Bold)
|
|
warning = color.New(color.FgYellow, color.Bold)
|
|
info = color.New(color.FgCyan)
|
|
header = color.New(color.FgMagenta, color.Bold)
|
|
cmdColor = color.New(color.FgBlue, color.Bold)
|
|
// Command line flags
|
|
verbose bool
|
|
)
|
|
|
|
func showSpinner(message string) func() {
|
|
s := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
|
s.Suffix = " " + message
|
|
s.Color("cyan")
|
|
s.Start()
|
|
return func() {
|
|
s.Stop()
|
|
}
|
|
}
|
|
|
|
func runWithSpinner(message string, needsSudo bool, fn func() error) error {
|
|
var stop func()
|
|
cmdStarted := make(chan struct{})
|
|
|
|
if needsSudo {
|
|
// Start a goroutine to show spinner after sudo auth
|
|
go func() {
|
|
<-cmdStarted
|
|
fmt.Print("\r\033[K") // Clear the line
|
|
stop = showSpinner(message)
|
|
}()
|
|
} else {
|
|
stop = showSpinner(message)
|
|
}
|
|
|
|
err := fn()
|
|
|
|
if needsSudo {
|
|
close(cmdStarted)
|
|
// Give the spinner a moment to show progress
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
if stop != nil {
|
|
stop()
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func main() {
|
|
// Initialize universal package managers
|
|
pkg_manager.InitializeUniversalManagers()
|
|
|
|
// Create custom flag set
|
|
flags := flag.NewFlagSet("upm", flag.ExitOnError)
|
|
flags.Usage = printUsage
|
|
|
|
// Define flags
|
|
var universalPM string
|
|
flags.StringVar(&universalPM, "u", "", "Use universal package manager (snap/flatpak)")
|
|
flags.BoolVar(&verbose, "v", false, "Show verbose output")
|
|
|
|
// Find where the command starts (after flags)
|
|
commandStart := 1
|
|
for commandStart < len(os.Args) {
|
|
if !strings.HasPrefix(os.Args[commandStart], "-") {
|
|
break
|
|
}
|
|
commandStart++
|
|
}
|
|
|
|
// Parse only the flags before the command
|
|
if err := flags.Parse(os.Args[1:commandStart]); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Get command and its arguments (everything after the flags)
|
|
if commandStart >= len(os.Args) {
|
|
printUsage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
args := os.Args[commandStart:]
|
|
|
|
if universalPM != "" {
|
|
if mgr, ok := pkg_manager.GetUniversalManager(universalPM); ok {
|
|
handleCommand(&mgr.Manager, args)
|
|
return
|
|
}
|
|
fmt.Fprintf(os.Stderr, "Universal package manager %s not available\n", universalPM)
|
|
os.Exit(1)
|
|
}
|
|
|
|
pm, err := pkg_manager.DetectPackageManager()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
handleCommand(pm, args)
|
|
}
|
|
|
|
func handleCommand(pm *pkg_manager.Manager, args []string) {
|
|
// Set output mode based on verbose flag
|
|
if verbose {
|
|
pkg_manager.SetOutputMode(pkg_manager.OutputVerbose)
|
|
} else {
|
|
pkg_manager.SetOutputMode(pkg_manager.OutputQuiet)
|
|
}
|
|
|
|
if len(args) == 0 {
|
|
printUsage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
command := args[0]
|
|
// Filter out any arguments that look like flags
|
|
var cmdArgs []string
|
|
for _, arg := range args[1:] {
|
|
if !strings.HasPrefix(arg, "-") {
|
|
cmdArgs = append(cmdArgs, arg)
|
|
}
|
|
}
|
|
|
|
switch command {
|
|
case "install":
|
|
if len(cmdArgs) == 0 {
|
|
errorColor.Fprintln(os.Stderr, "Error: no packages specified")
|
|
os.Exit(1)
|
|
}
|
|
err := runWithSpinner("Installing packages...", pm.NeedsSudo(), func() error {
|
|
return pm.Install(cmdArgs...)
|
|
})
|
|
if err != nil {
|
|
errorColor.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
success.Printf("✓ Successfully installed: %s\n", strings.Join(cmdArgs, ", "))
|
|
|
|
case "remove":
|
|
if len(cmdArgs) == 0 {
|
|
errorColor.Fprintln(os.Stderr, "Error: no packages specified")
|
|
os.Exit(1)
|
|
}
|
|
err := runWithSpinner("Removing packages...", pm.NeedsSudo(), func() error {
|
|
return pm.Remove(cmdArgs...)
|
|
})
|
|
if err != nil {
|
|
errorColor.Fprintf(os.Stderr, "Failed to remove packages: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
success.Printf("✓ Successfully removed: %s\n", strings.Join(cmdArgs, ", "))
|
|
|
|
case "search":
|
|
if len(cmdArgs) == 0 {
|
|
fmt.Fprintln(os.Stderr, "Error: search term required")
|
|
os.Exit(1)
|
|
}
|
|
if err := pm.Search(strings.Join(cmdArgs, " ")); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Search failed: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "update":
|
|
if err := pm.Update(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to update package lists: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "upgrade":
|
|
if err := pm.Upgrade(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to upgrade packages: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "list":
|
|
if err := pm.ListInstalled(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to list packages: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "info":
|
|
if len(cmdArgs) == 0 {
|
|
fmt.Fprintln(os.Stderr, "Error: package name required")
|
|
os.Exit(1)
|
|
}
|
|
if err := pm.ShowInfo(cmdArgs[0]); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to show package info: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "repo":
|
|
if len(cmdArgs) < 1 {
|
|
fmt.Fprintln(os.Stderr, "Error: repo subcommand required (add/remove/list)")
|
|
os.Exit(1)
|
|
}
|
|
switch cmdArgs[0] {
|
|
case "add":
|
|
if len(cmdArgs) < 2 {
|
|
fmt.Fprintln(os.Stderr, "Error: repository URL required")
|
|
os.Exit(1)
|
|
}
|
|
if err := pm.AddRepository(cmdArgs[1]); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to add repository: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
case "remove":
|
|
if len(cmdArgs) < 2 {
|
|
fmt.Fprintln(os.Stderr, "Error: repository name required")
|
|
os.Exit(1)
|
|
}
|
|
if err := pm.RemoveRepository(cmdArgs[1]); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to remove repository: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
case "list":
|
|
if err := pm.ListRepositories(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to list repositories: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "Unknown repo subcommand: %s\n", cmdArgs[0])
|
|
printUsage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "clean":
|
|
if err := pm.CleanCache(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to clean cache: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "autoremove":
|
|
if err := pm.AutoRemove(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to remove unused dependencies: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "check-deps":
|
|
pkg := ""
|
|
if len(cmdArgs) > 0 {
|
|
pkg = cmdArgs[0]
|
|
}
|
|
if err := pm.CheckDependencies(pkg); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Dependency check failed: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "show-deps":
|
|
if len(cmdArgs) == 0 {
|
|
fmt.Fprintln(os.Stderr, "Error: package name required")
|
|
os.Exit(1)
|
|
}
|
|
if err := pm.ShowDependencies(cmdArgs[0]); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to show dependencies: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
case "source":
|
|
if len(cmdArgs) == 0 {
|
|
fmt.Fprintln(os.Stderr, "Error: package name required")
|
|
os.Exit(1)
|
|
}
|
|
if err := pm.HandleSource(cmdArgs[0]); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to search source: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "Unknown command: %s\n", command)
|
|
printUsage()
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func printUsage() {
|
|
header.Println("\n📦 Universal Package Manager")
|
|
fmt.Println("\nUsage: upm [-u snap|flatpak] [-v] <command> [arguments]")
|
|
|
|
info.Println("\nCommands:")
|
|
cmdColor.Print(" install ")
|
|
fmt.Println("<package1[@version]> [package2[@version]...] - Install packages")
|
|
cmdColor.Print(" remove ")
|
|
fmt.Println("<package1> [package2...] - Remove packages")
|
|
cmdColor.Print(" search ")
|
|
fmt.Println("<term> - Search for packages")
|
|
cmdColor.Print(" update ")
|
|
fmt.Println(" - Update package lists")
|
|
cmdColor.Print(" upgrade ")
|
|
fmt.Println(" - Upgrade installed packages")
|
|
cmdColor.Print(" list ")
|
|
fmt.Println(" - List installed packages")
|
|
cmdColor.Print(" info ")
|
|
fmt.Println("<package> - Show package information")
|
|
|
|
info.Println("\nRepository Management:")
|
|
cmdColor.Print(" repo add ")
|
|
fmt.Println("<url> - Add repository")
|
|
cmdColor.Print(" repo remove ")
|
|
fmt.Println("<name> - Remove repository")
|
|
cmdColor.Print(" repo list ")
|
|
fmt.Println(" - List repositories")
|
|
|
|
info.Println("\nMaintenance:")
|
|
cmdColor.Print(" clean ")
|
|
fmt.Println(" - Clean package cache")
|
|
cmdColor.Print(" autoremove ")
|
|
fmt.Println(" - Remove unused dependencies")
|
|
|
|
info.Println("\nDependency Management:")
|
|
cmdColor.Print(" check-deps ")
|
|
fmt.Println("[package] - Check dependencies")
|
|
cmdColor.Print(" show-deps ")
|
|
fmt.Println("<package> - Show package dependencies")
|
|
|
|
info.Println("\nFlags:")
|
|
fmt.Println(" -u string Use universal package manager (snap/flatpak)")
|
|
fmt.Println(" -v Show verbose output")
|
|
|
|
warning.Println("\nExamples:")
|
|
fmt.Println(" upm install nginx@1.18.0")
|
|
fmt.Println(" upm -u snap install firefox")
|
|
fmt.Println(" upm repo add https://repo.example.com")
|
|
fmt.Println(" upm show-deps nginx")
|
|
fmt.Println()
|
|
}
|