Major update 4

This should be the final code update before we start testing things.
I think all the code is now in place to have the program function, barring any bugs in my code.

So, with that said, here's the changelog:

global changes:
```
- implement logger.go across the whole program
```

changes to main.go:
```
- add an import for strings
- implement the roughed in handling functions
```

changes to logger.go:
```
- create this little helper package to just handle all our logging nice and gracefully
```

changes to all_updater.go:
```
- basically completely redone. Accomplishes the same thing, just in a different, more efficient way.
```

changes to aur.go:
```
- add a function to clear the AllPac build cache for aur
```

changes to install.go:
```
- removed a duplicate function, set install.go to call the right one
```

changes to pacman.go:
```
- removed GetVersionFromPacman function (it shouldn't be here, it should be in search.go)
```

changes to search.go:
```
- add functions for getting info from, and parsing output from Snap, Pacman, Flatpak, and aur
```
This commit is contained in:
VetheonGames 2024-01-04 19:17:43 -07:00
parent 4b0a6e6d59
commit 50af1b9613
11 changed files with 610 additions and 71 deletions

View File

@ -6,6 +6,7 @@ import (
"flag"
"fmt"
"os"
"strings"
"pixelridgesoftworks.com/AllPac/pkg/packagemanager"
)
@ -70,27 +71,195 @@ func handleUpdate(cmd *flag.FlagSet) {
}
}
// handles the install command for packages
func handleInstall(cmd *flag.FlagSet) {
// Parse and handle the install command
// Use functions from install to install packages
packageNames := cmd.String("packages", "", "Comma-separated list of packages to install")
cmd.Parse(os.Args[2:])
if *packageNames == "" {
fmt.Println("You must specify at least one package name.")
cmd.Usage()
return
}
packages := strings.Split(*packageNames, ",")
searchResults, err := packagemanager.SearchAllSources(packages)
if err != nil {
fmt.Printf("Error searching for packages: %v\n", err)
return
}
for _, result := range searchResults {
fmt.Printf("Searching for package: %s\n", result.PackageName)
if len(result.Results) == 0 {
fmt.Println("No sources found for package.")
continue
}
sourceIndex := promptUserForSource(result.Results)
if sourceIndex < 0 || sourceIndex >= len(result.Results) {
fmt.Println("Invalid selection. Skipping package.")
continue
}
selectedSource := result.Results[sourceIndex].Source
fmt.Printf("Installing %s from %s...\n", result.PackageName, selectedSource)
switch selectedSource {
case "pacman":
err = packagemanager.InstallPackagePacman(result.PackageName)
case "snap":
err = packagemanager.InstallPackageSnap(result.PackageName)
case "flatpak":
err = packagemanager.InstallPackageFlatpak(result.PackageName)
case "aur":
_, err = packagemanager.CloneAndInstallFromAUR(fmt.Sprintf("https://aur.archlinux.org/%s.git", result.PackageName), false)
default:
fmt.Printf("Unknown source for package %s\n", result.PackageName)
continue
}
if err != nil {
fmt.Printf("Error installing package %s from %s: %v\n", result.PackageName, selectedSource, err)
} else {
fmt.Printf("Package %s installed successfully from %s.\n", result.PackageName, selectedSource)
}
}
}
// handleUninstall handles the uninstall command for packages
func handleUninstall(cmd *flag.FlagSet) {
// Parse and handle the uninstall command
// Use functions from packagemanager to uninstall packages
// Define a flag for accepting multiple package names
packageNames := cmd.String("packages", "", "Comma-separated list of packages to uninstall")
// Parse the command line arguments
cmd.Parse(os.Args[2:])
// Check if the package names were provided
if *packageNames == "" {
fmt.Println("You must specify at least one package name.")
cmd.Usage()
return
}
// Split the package names and convert to a slice
packages := strings.Split(*packageNames, ",")
// Call the function to uninstall the packages
err := packagemanager.UninstallPackages(packages)
if err != nil {
fmt.Printf("Error uninstalling packages: %v\n", err)
} else {
fmt.Println("Requested packages uninstalled successfully.")
}
}
// handleSearch handles the search command for packages across different package managers
func handleSearch(cmd *flag.FlagSet) {
// Parse and handle the search command
// Use functions from search to search for packages
// Define a flag for the package name
packageName := cmd.String("package", "", "Name of the package to search")
// Parse the command line arguments
cmd.Parse(os.Args[2:])
// Check if the package name was provided
if *packageName == "" {
fmt.Println("You must specify a package name.")
cmd.Usage()
return
}
// Search in Pacman
pacmanResults, err := packagemanager.SearchPacman(*packageName)
if err != nil {
fmt.Printf("Error searching in Pacman: %v\n", err)
} else {
fmt.Println("Pacman Results:")
for _, result := range pacmanResults {
fmt.Println(result)
}
}
// Search in Snap
snapResults, err := packagemanager.SearchSnap(*packageName)
if err != nil {
fmt.Printf("Error searching in Snap: %v\n", err)
} else {
fmt.Println("Snap Results:")
for _, result := range snapResults {
fmt.Println(result)
}
}
// Search in Flatpak
flatpakResults, err := packagemanager.SearchFlatpak(*packageName)
if err != nil {
fmt.Printf("Error searching in Flatpak: %v\n", err)
} else {
fmt.Println("Flatpak Results:")
for _, result := range flatpakResults {
fmt.Println(result)
}
}
// Search in AUR
aurResults, err := packagemanager.SearchAUR(*packageName)
if err != nil {
fmt.Printf("Error searching in AUR: %v\n", err)
} else {
fmt.Println("AUR Results:")
for _, result := range aurResults {
fmt.Printf("%s - %s\n", result.Name, result.Version)
}
}
}
// handleRebuild handles the rebuild command for an AUR package
func handleRebuild(cmd *flag.FlagSet) {
// Parse and handle the search command
// Use functions from search to search for packages
// Define a flag for the package name
packageName := cmd.String("package", "", "Name of the AUR package to rebuild")
// Parse the command line arguments
cmd.Parse(os.Args[2:])
// Check if the package name was provided
if *packageName == "" {
fmt.Println("You must specify a package name.")
cmd.Usage()
return
}
func handleCleanAur(cmd *flag.FlagSet) {
// Parse and handle the search command
// Use functions from search to search for packages
// Call the function to rebuild and reinstall the AUR package
err := packagemanager.RebuildAndReinstallAURPackage(*packageName)
if err != nil {
fmt.Printf("Error rebuilding package %s: %v\n", *packageName, err)
} else {
fmt.Printf("Package %s rebuilt and reinstalled successfully.\n", *packageName)
}
}
// handleCleanAur handles the cleaning of AUR cache
func handleCleanAur(cmd *flag.FlagSet) {
// Parse the command flags if needed
cmd.Parse(os.Args[2:])
// Call the function to clear the AUR cache
err := packagemanager.ClearAllPacCache()
if err != nil {
fmt.Printf("Error clearing AUR cache: %v\n", err)
return
}
fmt.Println("AUR cache cleared successfully.")
}
// prompts the user to select a source for installation
func promptUserForSource(sources []packagemanager.SourceResult) int {
for i, source := range sources {
fmt.Printf("%d: %s\n", i, source.Source)
}
fmt.Print("Select the source number to install from: ")
var choice int
fmt.Scan(&choice)
return choice
}

59
pkg/logger/logger.go Normal file
View File

@ -0,0 +1,59 @@
package logger
import (
"io"
"log"
"os"
"path/filepath"
"fmt"
)
var Logger *log.Logger
func Init(logFilePath string) error {
if err := os.MkdirAll(filepath.Dir(logFilePath), 0755); err != nil {
return err
}
logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return err
}
Logger = log.New(logFile, "AllPac: ", log.Ldate|log.Ltime|log.Lshortfile)
Logger.SetOutput(io.MultiWriter(os.Stderr, logFile))
return nil
}
func Info(v ...interface{}) {
Logger.Println("INFO: " + fmt.Sprint(v...))
}
func Infof(format string, v ...interface{}) {
Logger.Printf("INFO: "+format, v...)
}
func Warn(v ...interface{}) {
Logger.Println("WARN: " + fmt.Sprint(v...))
}
func Warnf(format string, v ...interface{}) {
Logger.Printf("WARN: "+format, v...)
}
func Error(v ...interface{}) {
Logger.Println("ERROR: " + fmt.Sprint(v...))
}
func Errorf(format string, v ...interface{}) {
Logger.Printf("ERROR: "+format, v...)
}
func Debug(v ...interface{}) {
Logger.Println("DEBUG: " + fmt.Sprint(v...))
}
func Debugf(format string, v ...interface{}) {
Logger.Printf("DEBUG: "+format, v...)
}

View File

@ -3,44 +3,126 @@ package packagemanager
import (
"fmt"
"sync"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// UpdateAllPackages updates all packages on the system
func UpdateAllPackages() error {
pkgList, err := readPackageList()
if err != nil {
logger.Errorf("Failed to load config: %v", err)
return fmt.Errorf("error reading package list: %v", err)
}
var wg sync.WaitGroup
for pkgName, pkgInfo := range pkgList {
wg.Add(1)
go func(name string, info PackageInfo) {
defer wg.Done()
if err := checkAndUpdatePackage(name, info); err != nil {
fmt.Printf("Error updating package %s: %v\n", name, err)
// Categorize packages by their source
pacmanPackages, aurPackages, snapPackages, flatpakPackages := separatePackagesBySource(pkgList)
// Check and collect packages that need updating for each category
pacmanToUpdate := checkPackagesForUpdate(pacmanPackages, "pacman")
snapToUpdate := checkPackagesForUpdate(snapPackages, "snap")
flatpakToUpdate := checkPackagesForUpdate(flatpakPackages, "flatpak")
// Perform batch updates
if err := UpdatePacmanPackages(pacmanToUpdate...); err != nil {
logger.Errorf("Error updating Pacman packages: %v\n", err)
}
}(pkgName, pkgInfo)
if err := UpdateSnapPackages(snapToUpdate...); err != nil {
logger.Errorf("Error updating Snap packages: %v\n", err)
}
if err := UpdateFlatpakPackages(flatpakToUpdate...); err != nil {
logger.Errorf("Error updating Flatpak packages: %v\n", err)
}
wg.Wait()
// Update AUR packages (can be done concurrently)
updateAURPackagesConcurrently(aurPackages)
fmt.Println("All packages have been updated.")
logger.Info("All packages have been updated.")
return nil
}
// checkAndUpdatePackage checks if an update is available for the package and updates it
func checkAndUpdatePackage(name string, info PackageInfo) error {
// Implement logic to check for the latest version and update
return nil
// separatePackagesBySource categorizes package names by their source
func separatePackagesBySource(pkgList PackageList) ([]string, []string, []string, []string) {
var pacmanPackages, aurPackages, snapPackages, flatpakPackages []string
for pkgName, pkgInfo := range pkgList {
switch pkgInfo.Source {
case "pacman":
pacmanPackages = append(pacmanPackages, pkgName)
case "aur":
aurPackages = append(aurPackages, pkgName)
case "snap":
snapPackages = append(snapPackages, pkgName)
case "flatpak":
flatpakPackages = append(flatpakPackages, pkgName)
}
}
return pacmanPackages, aurPackages, snapPackages, flatpakPackages
}
// functions to get the latest version for each package manager
func getLatestPacmanVersion(packageName string) (string, error) {
// Use SearchPacman to get the latest version
// Parse the output to extract the version
// Return the version
// ...
return "", nil
// checkPackagesForUpdate checks which packages need updating and returns their names
func checkPackagesForUpdate(packageNames []string, source string) []string {
var toUpdate []string
for _, name := range packageNames {
if needsUpdate, _ := checkIfPackageNeedsUpdate(name, source); needsUpdate {
toUpdate = append(toUpdate, name)
}
}
return toUpdate
}
// Similar implementations for getLatestAURVersion, getLatestSnapVersion, getLatestFlatpakVersion
// checkIfPackageNeedsUpdate checks if a given package needs an update
func checkIfPackageNeedsUpdate(name, source string) (bool, error) {
var currentVersion, latestVersion string
var err error
// Retrieve the current version of the package from the package list
pkgList, err := readPackageList()
if err != nil {
logger.Errorf("error reading package list: %v", err)
return false, fmt.Errorf("error reading package list: %v", err)
}
if pkgInfo, exists := pkgList[name]; exists {
currentVersion = pkgInfo.Version
} else {
logger.Errorf("package %s not found in package list", name)
return false, fmt.Errorf("package %s not found in package list", name)
}
// Get the latest version based on the source
switch source {
case "pacman":
latestVersion, err = GetPacmanPackageVersion(name)
case "aur":
latestVersion, err = GetAURPackageVersion(name)
case "snap":
latestVersion, err = GetSnapPackageVersion(name)
case "flatpak":
latestVersion, err = GetFlatpakPackageVersion(name)
default:
logger.Errorf("unknown package source for %s", name)
return false, fmt.Errorf("unknown package source for %s", name)
}
if err != nil {
logger.Errorf("An error has occured:", err)
return false, err
}
// Compare the current version with the latest version
return currentVersion != latestVersion, nil
}
// updateAURPackagesConcurrently updates AUR packages using concurrency
func updateAURPackagesConcurrently(packageNames []string) {
var wg sync.WaitGroup
for _, pkgName := range packageNames {
wg.Add(1)
go func(name string) {
defer wg.Done()
if err := UpdateAURPackages(name); err != nil {
logger.Errorf("Error updating AUR package %s: %v\n", name, err)
}
}(pkgName)
}
wg.Wait()
}

View File

@ -3,6 +3,9 @@ package packagemanager
import (
"fmt"
"os/exec"
"os"
"path/filepath"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// AURPackageInfo represents the package information from the AUR
@ -15,12 +18,14 @@ type AURPackageInfo struct {
func UpdateAURPackages(packageNames ...string) error {
pkgList, err := ReadPackageList()
if err != nil {
logger.Errorf("error reading package list: %v", err)
return fmt.Errorf("error reading package list: %v", err)
}
for _, packageName := range packageNames {
aurInfo, err := fetchAURPackageInfo(packageName)
if err != nil {
logger.Errorf("error fetching AUR package info for %s: %v", packageName, err)
return fmt.Errorf("error fetching AUR package info for %s: %v", packageName, err)
}
@ -28,6 +33,7 @@ func UpdateAURPackages(packageNames ...string) error {
if !ok || installedInfo.Version != aurInfo.Version {
_, err := CloneAndInstallFromAUR("https://aur.archlinux.org/" + packageName + ".git", true)
if err != nil {
logger.Errorf("error updating AUR package %s: %v", packageName, err)
return fmt.Errorf("error updating AUR package %s: %v", packageName, err)
}
}
@ -40,7 +46,59 @@ func UninstallAURPackage(packageName string) error {
// Uninstalling an AUR package is typically done with pacman
cmd := exec.Command("sudo", "pacman", "-Rns", "--noconfirm", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error uninstalling AUR package: %s, %v", output, err)
return fmt.Errorf("error uninstalling AUR package: %s, %v", output, err)
}
return nil
}
// ClearAllPacCache clears the contents of the ~/.allpac/cache/ directory
func ClearAllPacCache() error {
cacheDir, err := getCacheDir()
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
// Remove the directory and its contents
err = os.RemoveAll(cacheDir)
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
// Optionally, recreate the cache directory after clearing it
return os.MkdirAll(cacheDir, 0755)
}
// getCacheDir returns the path to the ~/.allpac/cache/ directory
func getCacheDir() (string, error) {
userHomeDir, err := os.UserHomeDir()
if err != nil {
logger.Errorf("An error has occured:", err)
return "", err
}
return filepath.Join(userHomeDir, ".allpac", "cache"), nil
}
// RebuildAndReinstallAURPackage rebuilds and reinstalls the specified AUR package
func RebuildAndReinstallAURPackage(packageName string) error {
// Read the package list
pkgList, err := readPackageList()
if err != nil {
logger.Errorf("error reading package list: %v", err)
return fmt.Errorf("error reading package list: %v", err)
}
// Check if the package is in the list and is an AUR package
pkgInfo, found := pkgList[packageName]
if !found || pkgInfo.Source != "aur" {
logger.Errorf("package %s is not found or not an AUR package", packageName)
return fmt.Errorf("package %s is not found or not an AUR package", packageName)
}
// Rebuild and reinstall the package
_, err = CloneAndInstallFromAUR(fmt.Sprintf("https://aur.archlinux.org/%s.git", packageName), false)
logger.Errorf("An error has occured:", err)
return err
}

View File

@ -6,6 +6,7 @@ import (
"os/exec"
"fmt"
"strings"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// UpdateFlatpakPackages updates specified Flatpak packages or all if no specific package is provided
@ -19,6 +20,7 @@ func UpdateFlatpakPackages(packageNames ...string) error {
}
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error updating Flatpak packages: %s, %v", output, err)
return fmt.Errorf("error updating Flatpak packages: %s, %v", output, err)
}
return nil
@ -28,6 +30,7 @@ func UpdateFlatpakPackages(packageNames ...string) error {
func UninstallFlatpakPackage(packageName string) error {
cmd := exec.Command("flatpak", "uninstall", "-y", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error uninstalling Flatpak package: %s, %v", output, err)
return fmt.Errorf("error uninstalling Flatpak package: %s, %v", output, err)
}
return nil
@ -38,6 +41,7 @@ func GetVersionFromFlatpak(applicationID string) (string, error) {
cmd := exec.Command("flatpak", "info", applicationID)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error getting flatpak package info: %v", err)
return "", fmt.Errorf("error getting flatpak package info: %v", err)
}
@ -51,5 +55,6 @@ func GetVersionFromFlatpak(applicationID string) (string, error) {
break
}
}
logger.Errorf("version not found for flatpak package: %s", applicationID)
return "", fmt.Errorf("version not found for flatpak package: %s", applicationID)
}

View File

@ -10,21 +10,25 @@ import (
"os/exec"
"os/user"
"path/filepath"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// InstallPackagePacman installs a package using Pacman and logs the installation
func InstallPackagePacman(packageName string) error {
cmd := exec.Command("sudo", "pacman", "-S", "--noconfirm", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error installing package with Pacman: %s, %v", output, err)
return fmt.Errorf("error installing package with Pacman: %s, %v", output, err)
}
version, err := GetVersionFromPacman(packageName)
version, err := GetPacmanPackageVersion(packageName)
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
if err := LogInstallation(packageName, "pacman", version); err != nil {
logger.Errorf("error logging installation: %v", err)
return fmt.Errorf("error logging installation: %v", err)
}
return nil
@ -34,15 +38,18 @@ func InstallPackagePacman(packageName string) error {
func InstallPackageSnap(packageName string) error {
cmd := exec.Command("sudo", "snap", "install", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error installing package with Snap: %s, %v", output, err)
return fmt.Errorf("error installing package with Snap: %s, %v", output, err)
}
version, err := GetVersionFromSnap(packageName)
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
if err := LogInstallation(packageName, "snap", version); err != nil {
logger.Errorf("error logging installation: %v", err)
return fmt.Errorf("error logging installation: %v", err)
}
return nil
@ -52,15 +59,18 @@ func InstallPackageSnap(packageName string) error {
func InstallPackageFlatpak(packageName string) error {
cmd := exec.Command("flatpak", "install", "-y", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error installing package with Flatpak: %s, %v", output, err)
return fmt.Errorf("error installing package with Flatpak: %s, %v", output, err)
}
version, err := GetVersionFromFlatpak(packageName)
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
if err := LogInstallation(packageName, "flatpak", version); err != nil {
logger.Errorf("error logging installation: %v", err)
return fmt.Errorf("error logging installation: %v", err)
}
return nil
@ -70,16 +80,19 @@ func InstallPackageFlatpak(packageName string) error {
func CloneAndInstallFromAUR(repoURL string, skipConfirmation bool) (string, error) {
// Request root permissions
if !skipConfirmation && !requestRootPermissions() {
logger.Warnf("root permissions denied")
return "", fmt.Errorf("root permissions denied")
}
// Confirm before proceeding with each step
if !skipConfirmation && !confirmAction("Do you want to download and build package from " + repoURL + "?") {
logger.Warnf("user aborted the action")
return "", fmt.Errorf("user aborted the action")
}
// Get the current user's home directory
usr, err := user.Current()
if err != nil {
logger.Errorf("error getting current user: %v", err)
return "", fmt.Errorf("error getting current user: %v", err)
}
@ -88,12 +101,14 @@ func CloneAndInstallFromAUR(repoURL string, skipConfirmation bool) (string, erro
// Ensure the base directory exists
if err := os.MkdirAll(baseDir, 0755); err != nil {
logger.Errorf("error creating base directory: %v", err)
return "", fmt.Errorf("error creating base directory: %v", err)
}
// Clone the repository
cmdGitClone := exec.Command("git", "clone", repoURL, baseDir)
if output, err := cmdGitClone.CombinedOutput(); err != nil {
logger.Errorf("error cloning AUR repo: %s, %v", output, err)
return "", fmt.Errorf("error cloning AUR repo: %s, %v", output, err)
}
@ -103,27 +118,32 @@ func CloneAndInstallFromAUR(repoURL string, skipConfirmation bool) (string, erro
// Change directory to the cloned repository
if err := os.Chdir(repoDir); err != nil {
logger.Errorf("error changing directory: %v", err)
return "", fmt.Errorf("error changing directory: %v", err)
}
// Build the package using makepkg
cmdMakePkg := exec.Command("makepkg", "-si", "--noconfirm")
if output, err := cmdMakePkg.CombinedOutput(); err != nil {
logger.Errorf("error building package with makepkg: %s, %v", output, err)
return "", fmt.Errorf("error building package with makepkg: %s, %v", output, err)
}
// Extract the version from PKGBUILD
version, err := ExtractVersionFromPKGBUILD(repoDir)
if err != nil {
logger.Errorf("error extracting version from PKGBUILD: %v", err)
return "", fmt.Errorf("error extracting version from PKGBUILD: %v", err)
}
// Confirm before installing
if !skipConfirmation && !confirmAction("Do you want to install the built package " + repoName + "?") {
logger.Warnf("user aborted the installation")
return "", fmt.Errorf("user aborted the installation")
}
if err := LogInstallation(repoName, "aur", version); err != nil {
logger.Errorf("error logging installation")
return "", fmt.Errorf("error logging installation: %v", err)
}
@ -134,10 +154,12 @@ func CloneAndInstallFromAUR(repoURL string, skipConfirmation bool) (string, erro
func InstallSnap() error {
version, err := CloneAndInstallFromAUR("https://aur.archlinux.org/snapd.git", true)
if err != nil {
logger.Errorf("error installing Snap: %v", err)
return fmt.Errorf("error installing Snap: %v", err)
}
if err := LogInstallation("snapd", "aur", version); err != nil {
logger.Errorf("error logging installation")
return fmt.Errorf("error logging installation: %v", err)
}
return nil
@ -146,6 +168,7 @@ func InstallSnap() error {
// InstallGit installs Git using Pacman
func InstallGit() error {
if err := InstallPackagePacman("git"); err != nil {
logger.Errorf("error installing Git: %v", err)
return fmt.Errorf("error installing Git: %v", err)
}
return nil
@ -154,6 +177,7 @@ func InstallGit() error {
// InstallBaseDevel installs the base-devel group using Pacman
func InstallBaseDevel() error {
if err := InstallPackagePacman("base-devel"); err != nil {
logger.Errorf("error installing base-devel: %v", err)
return fmt.Errorf("error installing base-devel: %v", err)
}
return nil
@ -162,6 +186,7 @@ func InstallBaseDevel() error {
// InstallFlatpak installs the Flatpak package using Pacman
func InstallFlatpak() error {
if err := InstallPackagePacman("flatpak"); err != nil {
logger.Errorf("error installing flatpak: %v", err)
return fmt.Errorf("error installing flatpak: %v", err)
}
return nil

View File

@ -8,6 +8,7 @@ import (
"strings"
"fmt"
"encoding/json"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// extractVersionFromPKGBUILD reads the PKGBUILD file and extracts the package version
@ -15,6 +16,7 @@ func ExtractVersionFromPKGBUILD(repoDir string) (string, error) {
pkgbuildPath := filepath.Join(repoDir, "PKGBUILD")
file, err := os.Open(pkgbuildPath)
if err != nil {
logger.Errorf("An error has occured:", err)
return "", err
}
defer file.Close()
@ -28,9 +30,11 @@ func ExtractVersionFromPKGBUILD(repoDir string) (string, error) {
}
if err := scanner.Err(); err != nil {
logger.Errorf("An error has occured:", err)
return "", err
}
logger.Errorf("pkgver not found in PKGBUILD")
return "", fmt.Errorf("pkgver not found in PKGBUILD")
}
@ -47,6 +51,7 @@ const pkgListFilename = "pkg.list"
func GetPkgListPath() (string, error) {
usr, err := user.Current()
if err != nil {
logger.Errorf("error getting current user: %v", err)
return "", fmt.Errorf("error getting current user: %v", err)
}
return filepath.Join(usr.HomeDir, ".allpac", pkgListFilename), nil
@ -56,6 +61,7 @@ func GetPkgListPath() (string, error) {
func ReadPackageList() (PackageList, error) {
pkgListPath, err := GetPkgListPath()
if err != nil {
logger.Errorf("An error has occured:", err)
return nil, err
}
@ -64,6 +70,7 @@ func ReadPackageList() (PackageList, error) {
if os.IsNotExist(err) {
return PackageList{}, nil // Return an empty list if file doesn't exist
}
logger.Errorf("error opening package list file: %v", err)
return nil, fmt.Errorf("error opening package list file: %v", err)
}
defer file.Close()
@ -71,6 +78,7 @@ func ReadPackageList() (PackageList, error) {
var pkgList PackageList
err = json.NewDecoder(file).Decode(&pkgList)
if err != nil {
logger.Errorf("error decoding package list: %v", err)
return nil, fmt.Errorf("error decoding package list: %v", err)
}
@ -81,17 +89,20 @@ func ReadPackageList() (PackageList, error) {
func writePackageList(pkgList PackageList) error {
pkgListPath, err := GetPkgListPath()
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
file, err := os.Create(pkgListPath)
if err != nil {
logger.Errorf("error creating package list file: %v", err)
return fmt.Errorf("error creating package list file: %v", err)
}
defer file.Close()
err = json.NewEncoder(file).Encode(pkgList)
if err != nil {
logger.Errorf("error encoding package list: %v", err)
return fmt.Errorf("error encoding package list: %v", err)
}
@ -102,6 +113,7 @@ func writePackageList(pkgList PackageList) error {
func LogInstallation(packageName, source, version string) error {
pkgList, err := readPackageList()
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
@ -126,6 +138,7 @@ func confirmAction(question string) bool {
fmt.Printf("%s [Y/n]: ", question)
response, err := reader.ReadString('\n')
if err != nil {
logger.Errorf("Error reading response: %v", err)
fmt.Println("Error reading response:", err)
return false
}

View File

@ -3,9 +3,10 @@ package packagemanager
// This package is responsible for handling updating and uninstalling pacman packages
import (
"os/exec"
"fmt"
"strings"
"os/exec"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// UpdatePacmanPackages updates specified Pacman packages or all if no specific package is provided
@ -19,6 +20,7 @@ func UpdatePacmanPackages(packageNames ...string) error {
}
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error updating Pacman packages: %s, %v", string(output), err)
return fmt.Errorf("error updating Pacman packages: %s, %v", string(output), err)
}
return nil
@ -28,23 +30,8 @@ func UpdatePacmanPackages(packageNames ...string) error {
func UninstallPacmanPackage(packageName string) error {
cmd := exec.Command("sudo", "pacman", "-Rns", "--noconfirm", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error uninstalling Pacman package: %s, %v", output, err)
return fmt.Errorf("error uninstalling Pacman package: %s, %v", output, err)
}
return nil
}
// getVersionFromPacman gets the installed version of a package using Pacman
func GetVersionFromPacman(packageName string) (string, error) {
cmd := exec.Command("pacman", "-Qi", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("error getting package version: %v", err)
}
for _, line := range strings.Split(string(output), "\n") {
if strings.HasPrefix(line, "Version") {
return strings.Fields(line)[2], nil
}
}
return "", fmt.Errorf("version not found for package: %s", packageName)
}

View File

@ -11,38 +11,45 @@ import (
"path/filepath"
"strings"
"net/http"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// UninstallPackages uninstalls the provided packages
// uninstalls the provided packages
func UninstallPackages(packageNames []string) error {
pkgList, err := readPackageList()
if err != nil {
logger.Errorf("An error has occured:", err)
return err
}
for _, packageName := range packageNames {
source, exists := pkgList[packageName]
pkgInfo, exists := pkgList[packageName]
if !exists {
logger.Warnf("Package %s not found in installed packages list\n", packageNames)
fmt.Printf("Package %s not found in installed packages list\n", packageName)
continue
}
switch source {
switch pkgInfo.Source {
case "pacman":
err = UninstallPacmanPackage(packageName)
case "snap":
err = UninstallSnapPackage(packageName)
case "flatpak":
err = UninstallFlatpakPackage(packageName)
// Add cases for other package managers if necessary
case "aur":
err = UninstallAURPackage(packageName)
default:
logger.Warnf("Unknown source for package %s\n", packageNames)
fmt.Printf("Unknown source for package %s\n", packageName)
continue
}
if err != nil {
logger.Warnf("Error uninstalling package %s: %v\n", packageName, err)
fmt.Printf("Error uninstalling package %s: %v\n", packageName, err)
} else {
logger.Infof("Successfully uninstalled package %s\n", packageName)
fmt.Printf("Successfully uninstalled package %s\n", packageName)
}
}
@ -50,29 +57,32 @@ func UninstallPackages(packageNames []string) error {
return nil
}
// readPackageList reads the package list from the pkg.list file
// reads the package list from the pkg.list file
func readPackageList() (PackageList, error) {
usr, err := user.Current()
if err != nil {
logger.Errorf("error getting current user: %v", err)
return nil, fmt.Errorf("error getting current user: %v", err)
}
pkgListPath := filepath.Join(usr.HomeDir, ".allpac", "pkg.list")
file, err := ioutil.ReadFile(pkgListPath)
if err != nil {
logger.Errorf("error reading package list file: %v", err)
return nil, fmt.Errorf("error reading package list file: %v", err)
}
var pkgList PackageList
err = json.Unmarshal(file, &pkgList)
if err != nil {
logger.Errorf("error decoding package list: %v", err)
return nil, fmt.Errorf("error decoding package list: %v", err)
}
return pkgList, nil
}
// AURResponse represents the structure of the response from AUR RPC
// represents the structure of the response from AUR RPC
type AURResponse struct {
Version int `json:"version"`
Type string `json:"type"`
@ -80,7 +90,7 @@ type AURResponse struct {
Results []AURPackage `json:"results"`
}
// AURPackage represents a package in the AUR
// represents a package in the AUR
type AURPackage struct {
ID int `json:"ID"`
Name string `json:"Name"`
@ -90,61 +100,64 @@ type AURPackage struct {
// Add other fields as needed
}
// SearchPacman searches for a package in the Pacman repositories
// searches for a package in the Pacman repositories
func SearchPacman(packageName string) ([]string, error) {
cmd := exec.Command("pacman", "-Ss", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error searching Pacman: %v", err)
return nil, fmt.Errorf("error searching Pacman: %v", err)
}
return parsePacmanOutput(string(output)), nil
}
// SearchSnap searches for a package in the Snap store
// searches for a package in the Snap store
func SearchSnap(packageName string) ([]string, error) {
cmd := exec.Command("snap", "find", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error searching Snap: %v", err)
return nil, fmt.Errorf("error searching Snap: %v", err)
}
return strings.Split(string(output), "\n"), nil
}
// SearchFlatpak searches for a package in Flatpak repositories
// searches for a package in Flatpak repositories
func SearchFlatpak(packageName string) ([]string, error) {
cmd := exec.Command("flatpak", "search", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error searching Flatpak: %v", err)
return nil, fmt.Errorf("error searching Flatpak: %v", err)
}
return strings.Split(string(output), "\n"), nil
}
// SearchAUR searches the AUR for the given term
// searches the AUR for the given term
func SearchAUR(searchTerm string) ([]AURPackage, error) {
url := fmt.Sprintf("https://aur.archlinux.org/rpc/?v=5&type=search&arg=%s", searchTerm)
resp, err := http.Get(url)
if err != nil {
logger.Errorf("error making request to AUR: %v", err)
return nil, fmt.Errorf("error making request to AUR: %v", err)
}
defer resp.Body.Close()
var aurResponse AURResponse
if err := json.NewDecoder(resp.Body).Decode(&aurResponse); err != nil {
logger.Errorf("error decoding AUR response: %v", err)
return nil, fmt.Errorf("error decoding AUR response: %v", err)
}
return aurResponse.Results, nil
}
// parsePacmanOutput parses the output from Pacman search command
// parses the output from Pacman search command
func parsePacmanOutput(output string) []string {
// Split the output into sections, each representing a package
sections := strings.Split(output, "\n\n")
var packages []string
for _, section := range sections {
// Split each section into lines
lines := strings.Split(section, "\n")
// The first line should contain the package name and version
@ -163,10 +176,11 @@ func parsePacmanOutput(output string) []string {
return packages
}
// GetPacmanPackageVersion returns the version of a package in the Pacman repositories
// returns the version of a package in the Pacman repositories
func GetPacmanPackageVersion(packageName string) (string, error) {
searchResults, err := SearchPacman(packageName)
if err != nil {
logger.Errorf("An error has occured:", err)
return "", err
}
@ -176,24 +190,26 @@ func GetPacmanPackageVersion(packageName string) (string, error) {
}
}
logger.Errorf("package %s not found in Pacman", packageName)
return "", fmt.Errorf("package %s not found in Pacman", packageName)
}
// extractVersionFromPacmanResult extracts the version from a Pacman search result string
// extracts the version from a Pacman search result string
func extractVersionFromPacmanResult(result string) string {
// Assuming the result is in the format "packageName version description"
parts := strings.Fields(result)
if len(parts) >= 2 {
return parts[1] // The second element should be the version
return parts[1]
}
return ""
}
// fetchAURPackageInfo fetches package information from the AUR
// fetches package information from the AUR
func fetchAURPackageInfo(packageName string) (*AURPackageInfo, error) {
url := fmt.Sprintf("https://aur.archlinux.org/rpc/?v=5&type=info&arg[]=%s", packageName)
resp, err := http.Get(url)
if err != nil {
logger.Errorf("An error has occured:", err)
return nil, err
}
defer resp.Body.Close()
@ -202,12 +218,130 @@ func fetchAURPackageInfo(packageName string) (*AURPackageInfo, error) {
Results []AURPackageInfo `json:"results"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
logger.Errorf("An error has occured:", err)
return nil, err
}
if len(result.Results) == 0 {
logger.Errorf("package %s not found in AUR", packageName)
return nil, fmt.Errorf("package %s not found in AUR", packageName)
}
return &result.Results[0], nil
}
// returns the version of a package in the Snap store
func GetSnapPackageVersion(packageName string) (string, error) {
cmd := exec.Command("snap", "info", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error getting Snap package info: %v", err)
return "", fmt.Errorf("error getting Snap package info: %v", err)
}
return parseSnapInfoOutput(string(output)), nil
}
// parses the output from the Snap info command to extract the version
func parseSnapInfoOutput(output string) string {
lines := strings.Split(output, "\n")
for _, line := range lines {
if strings.HasPrefix(line, "installed:") {
parts := strings.Fields(line)
if len(parts) >= 2 {
return strings.TrimSpace(parts[1])
}
}
}
return ""
}
// returns the version of a package in Flatpak repositories
func GetFlatpakPackageVersion(packageName string) (string, error) {
cmd := exec.Command("flatpak", "info", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error getting Flatpak package info: %v", err)
return "", fmt.Errorf("error getting Flatpak package info: %v", err)
}
return parseFlatpakInfoOutput(string(output)), nil
}
// parses the output from the Flatpak info command to extract the version
func parseFlatpakInfoOutput(output string) string {
lines := strings.Split(output, "\n")
for _, line := range lines {
if strings.HasPrefix(line, "Version:") {
parts := strings.Fields(line)
if len(parts) >= 2 {
return strings.TrimSpace(parts[1])
}
}
}
return ""
}
// returns the version of a package in the AUR
func GetAURPackageVersion(packageName string) (string, error) {
aurInfo, err := fetchAURPackageInfo(packageName)
if err != nil {
logger.Errorf("An error has occured:", err)
return "", err
}
return aurInfo.Version, nil
}
// represents the search result from a specific source
type SourceResult struct {
Source string
Results []string
}
// represents the search results for a package across different sources
type PackageSearchResult struct {
PackageName string
Results []SourceResult
}
// searches for packages across Pacman, Snap, Flatpak, and AUR
func SearchAllSources(packageNames []string) ([]PackageSearchResult, error) {
var allPackageResults []PackageSearchResult
for _, packageName := range packageNames {
var packageResults PackageSearchResult
packageResults.PackageName = packageName
// Search in Pacman
pacmanResults, err := SearchPacman(packageName)
if err == nil {
packageResults.Results = append(packageResults.Results, SourceResult{"Pacman", pacmanResults})
}
// Search in Snap
snapResults, err := SearchSnap(packageName)
if err == nil {
packageResults.Results = append(packageResults.Results, SourceResult{"Snap", snapResults})
}
// Search in Flatpak
flatpakResults, err := SearchFlatpak(packageName)
if err == nil {
packageResults.Results = append(packageResults.Results, SourceResult{"Flatpak", flatpakResults})
}
// Search in AUR
aurResults, err := SearchAUR(packageName)
if err == nil {
var aurResultStrings []string
for _, result := range aurResults {
aurResultStrings = append(aurResultStrings, fmt.Sprintf("%s - %s", result.Name, result.Version))
}
packageResults.Results = append(packageResults.Results, SourceResult{"AUR", aurResultStrings})
}
allPackageResults = append(allPackageResults, packageResults)
}
return allPackageResults, nil
}

View File

@ -6,6 +6,7 @@ import (
"os/exec"
"fmt"
"strings"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// UpdateSnapPackages updates specified Snap packages or all if no specific package is provided
@ -19,6 +20,7 @@ func UpdateSnapPackages(packageNames ...string) error {
}
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error updating Snap packages: %s, %v", string(output), err)
return fmt.Errorf("error updating Snap packages: %s, %v", string(output), err)
}
return nil
@ -28,6 +30,7 @@ func UpdateSnapPackages(packageNames ...string) error {
func UninstallSnapPackage(packageName string) error {
cmd := exec.Command("sudo", "snap", "remove", packageName)
if output, err := cmd.CombinedOutput(); err != nil {
logger.Errorf("error uninstalling Snap package: %s, %v", string(output), err)
return fmt.Errorf("error uninstalling Snap package: %s, %v", string(output), err)
}
return nil
@ -38,6 +41,7 @@ func GetVersionFromSnap(packageName string) (string, error) {
cmd := exec.Command("snap", "info", packageName)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("error getting snap package info: %v", err)
return "", fmt.Errorf("error getting snap package info: %v", err)
}
@ -51,5 +55,6 @@ func GetVersionFromSnap(packageName string) (string, error) {
break
}
}
logger.Errorf("version not found for snap package: %s", packageName)
return "", fmt.Errorf("version not found for snap package: %s", packageName)
}

View File

@ -10,6 +10,7 @@ import (
"os/exec"
"fmt"
"pixelridgesoftworks.com/AllPac/pkg/packagemanager"
"pixelridgesoftworks.com/AllPac/pkg/logger"
)
// isCommandAvailable checks if a command exists
@ -24,6 +25,7 @@ func isCommandAvailable(name string) bool {
// EnsurePacman ensures that Pacman is installed and available
func EnsurePacman() error {
if !isCommandAvailable("pacman") {
logger.Errorf("pacman is not available, which is required for AllPac to function")
// Pacman should always be available on Arch-based systems, handle this as an error or special case
return fmt.Errorf("pacman is not available, which is required for AllPac to function")
}