Added deletion of packages

This commit is contained in:
Arzumify 2024-09-10 07:38:47 +01:00
parent 7b0aba2ad7
commit 39f15e7e1e
5 changed files with 1116 additions and 438 deletions

16
.vscode/launch.json vendored
View file

@ -1,16 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": [],
}
]
}

BIN
cmd/cmd

Binary file not shown.

View file

@ -6,27 +6,39 @@ import (
"eon/common"
"eon/lib"
"fmt"
"golang.org/x/term"
"io"
"os"
"regexp"
"sort"
"strings"
"math/big"
"net/http"
"net/url"
"os"
"regexp"
"strings"
"golang.org/x/sys/unix"
"golang.org/x/term"
"github.com/dustin/go-humanize"
"github.com/fatih/color"
)
var logger = &common.DefaultLogger
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: eon <list/info/install/remove/clean/repo/help> [args]")
os.Exit(1)
}
logger := &common.DefaultLogger
for i, arg := range os.Args {
if arg == "--help" || arg == "-h" || (i != 1 && arg == "help") {
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "To ask for help, use 'eon help <list/info/install/remove/clean/repo/help>', not --help, -h, or eon <command> help.",
})
}
}
switch os.Args[1] {
case "help":
if len(os.Args) < 3 {
@ -35,11 +47,11 @@ func main() {
} else {
switch os.Args[2] {
case "list":
fmt.Println("Usage: eon list (remote/local)")
fmt.Println("- remote: lists packages available in the repositories.")
fmt.Println("Usage: eon list (repo/local)")
fmt.Println("- repo: lists packages available in repositories.")
fmt.Println("- local: lists installed packages.")
case "info":
fmt.Println("Usage: eon info <package>")
fmt.Println("Usage: eon info <package> [(repo/local)] [<repository>]")
fmt.Println("Shows information about a package.")
case "install":
fmt.Println("Usage: eon install <package> [<repository>]")
@ -51,9 +63,9 @@ func main() {
fmt.Println("Usage: eon clean")
fmt.Println("Removes unused dependencies.")
case "repo":
fmt.Println("Usage: eon repo (add/remove/list)")
fmt.Println("Usage: eon repo (add/del/list)")
fmt.Println("- add <url>: adds a repository.")
fmt.Println("- remove <url>: removes a repository.")
fmt.Println("- del <name>: removes a repository.")
fmt.Println("- list: lists repositories.")
case "help":
fmt.Println("Usage: eon help (list/info/install/remove/clean/repo/help) [args]")
@ -65,6 +77,7 @@ func main() {
}
case "install":
var forceMode bool
var yesMode bool
var inMemoryMode bool
if len(os.Args) < 3 {
fmt.Println("Usage: eon install <package>")
@ -103,6 +116,8 @@ func main() {
forceMode = true
case "--optimizeForSpeed", "-O":
inMemoryMode = true
case "--yes", "-y":
yesMode = true
}
}
}
@ -126,18 +141,27 @@ func main() {
var epkList []common.InstallPackage
var skipEpkList [][]string
var dependencies int
localPackageListIteration:
for _, pkg := range localPackageList {
// Check if the package is already in epkList.
for _, epk := range epkList {
if epk.EPKPreMap.DisplayData.Name == pkg {
continue localPackageListIteration
}
}
epkFile, err := os.Open(pkg)
if err != nil {
fmt.Println(color.RedString("Failed to open package: " + err.Error()))
os.Exit(1)
}
var displayData lib.EPKPreMap
var preMap lib.EPKPreMap
var vagueErr error
var epkBytes bytes.Buffer
if !inMemoryMode {
displayData, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{FileStream: epkFile, IsFileStream: true}, fileInfos[pkg].Size())
preMap, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{FileStream: epkFile, IsFileStream: true}, fileInfos[pkg].Size())
} else {
_, err = io.Copy(bufio.NewWriter(&epkBytes), epkFile)
if err != nil {
@ -149,15 +173,29 @@ func main() {
if err != nil {
fmt.Println(color.HiYellowString("Failed to close package file: " + err.Error() + ", memory leak possible."))
}
displayData, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{Bytes: epkBytes.Bytes()}, fileInfos[pkg].Size())
preMap, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{Bytes: epkBytes.Bytes()}, fileInfos[pkg].Size())
}
if err != nil || vagueErr != nil {
common.PreMapEPKHandleError(err, vagueErr, logger)
os.Exit(1)
}
// Check if the architecture is supported.
var uts unix.Utsname
err = unix.Uname(&uts)
if err != nil {
fmt.Println(color.RedString("Failed to get system architecture: " + err.Error()))
os.Exit(1)
}
// Check if the architecture is supported.
if preMap.DisplayData.Architecture != "noarch" || preMap.DisplayData.Architecture != string(uts.Machine[:]) {
fmt.Println(color.RedString("Package architecture not supported: " + preMap.DisplayData.Architecture))
os.Exit(1)
}
var installPackage common.InstallPackage
installPackage.EPKPreMap = &displayData
installPackage.EPKPreMap = &preMap
installPackage.Url = ""
installPackage.Priority = 0
installPackage.IsRemote = false
@ -174,21 +212,23 @@ func main() {
}
installPackage.Repository = lib.Repository{Name: "Local file"}
displayData.IsUpgrade = true
preMap.IsUpgrade = true
version, exists, err := common.DefaultCheckEPKInDB(displayData.Name)
version, exists, err := common.DefaultCheckEPKInDB(preMap.DisplayData.Name)
if err != nil {
fmt.Println(color.RedString("Failed to check for package in database: " + err.Error()))
}
if exists {
if version.Compare(&displayData.Version) != -1 {
if version.Compare(&preMap.DisplayData.Version) != -1 {
if !forceMode {
skipEpk := []string{displayData.Name, displayData.Architecture, displayData.Version.String(), "Local file", humanize.BigIBytes(displayData.DecompressedSize), "Skip"}
skipEpk := []string{preMap.DisplayData.Name, preMap.DisplayData.Architecture, preMap.DisplayData.Version.String(), "Local file", humanize.BigIBytes(preMap.DisplayData.DecompressedSize), "Skip"}
skipEpkList = append(skipEpkList, skipEpk)
} else {
installPackage.IsForced = true
addedDeps, err := common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, &epkList, logger)
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -198,7 +238,9 @@ func main() {
epkList = append(epkList, installPackage)
}
} else {
addedDeps, err := common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, &epkList, logger)
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -208,8 +250,10 @@ func main() {
epkList = append(epkList, installPackage)
}
} else {
displayData.IsUpgrade = false
addedDeps, err := common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, &epkList, logger)
preMap.IsUpgrade = false
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -220,7 +264,15 @@ func main() {
}
}
repoPackageListIteration:
for _, pkg := range repoPackageList {
// Check if the package is already in epkList.
for _, epk := range epkList {
if epk.EPKPreMap.DisplayData.Name == pkg {
continue repoPackageListIteration
}
}
// Check if the package is already installed.
version, exists, err := common.DefaultCheckEPKInDB(pkg)
if err != nil {
@ -237,13 +289,20 @@ func main() {
os.Exit(1)
}
epkExists := false
for _, epk := range remoteEpkList {
if epk.Name == pkg {
remoteEPK = epk
epkExists = true
break
}
}
if !epkExists {
fmt.Println(color.RedString("Package not found: " + pkg))
os.Exit(1)
}
// Calculate the download URL
epkDownloadUrl, err := url.JoinPath(remoteEPK.Repository.URL, remoteEPK.Path)
if err != nil {
@ -253,15 +312,15 @@ func main() {
}
// Pre-map the EPK
displayData, err, vagueErr := lib.PreMapRemoteEPK(remoteEPK, logger)
preMap, err, vagueErr := lib.PreMapRemoteEPK(remoteEPK, logger)
if err != nil || vagueErr != nil {
common.PreMapEPKHandleError(err, vagueErr, logger)
common.PreMapRemoteEPKHandleError(err, vagueErr, logger)
os.Exit(1)
}
// Map the data we have
epkEntry.Priority = 0
epkEntry.EPKPreMap = &displayData
epkEntry.EPKPreMap = &preMap
epkEntry.Url = epkDownloadUrl
epkEntry.IsRemote = true
epkEntry.Repository = remoteEPK.Repository
@ -287,7 +346,7 @@ func main() {
contentLength.SetString(epkBytes.Header.Get("Content-Length"), 10)
// Print that we are downloading the package
fmt.Println("\nDownloading package: " + displayData.Name + " (" + humanize.BigIBytes(contentLength) + ")")
fmt.Println("\nDownloading package: " + preMap.DisplayData.Name + " (" + humanize.BigIBytes(contentLength) + ")")
// Hide the cursor for reasons explained below.
fmt.Print("\033[?25l")
@ -331,15 +390,17 @@ func main() {
// Make decisions on what happens if the package is already installed.
if exists {
if version.Compare(&displayData.Version) != -1 {
if version.Compare(&preMap.DisplayData.Version) != -1 {
// If the version is the same or newer, skip the package.
if !forceMode {
skipEpkList = append(skipEpkList, []string{displayData.Name, displayData.Architecture, displayData.Version.String(), remoteEPK.Repository.Name, humanize.BigIBytes(displayData.DecompressedSize), "Skip"})
skipEpkList = append(skipEpkList, []string{preMap.DisplayData.Name, preMap.DisplayData.Architecture, preMap.DisplayData.Version.String(), remoteEPK.Repository.Name, humanize.BigIBytes(preMap.DisplayData.DecompressedSize), "Skip"})
} else {
// If the version is the same or newer, but the user wants to force the installation, install it.
epkEntry.IsForced = true
// We can let it use our remoteEPKList to save a SQL query.
addedDeps, err := common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, &epkList, logger)
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -351,7 +412,9 @@ func main() {
}
} else {
// If the version is older, install it.
addedDeps, err := common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, &epkList, logger)
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -362,7 +425,9 @@ func main() {
}
} else {
// If the package is not installed, install it.
addedDeps, err := common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, &epkList, logger)
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -373,6 +438,14 @@ func main() {
}
}
// Sort the list of packages to install by priority, then alphabetically.
sort.Slice(epkList, func(i, j int) bool {
if epkList[i].Priority == epkList[j].Priority {
return epkList[i].EPKPreMap.DisplayData.Name < epkList[j].EPKPreMap.DisplayData.Name
}
return epkList[i].Priority > epkList[j].Priority
})
// Give the summary of the installation.
fmt.Println("\nThe following packages will be installed:")
width, _, err := term.GetSize(int(os.Stdout.Fd()))
@ -407,15 +480,15 @@ func main() {
for _, pkg := range epkList {
finalisedList := make([]string, 6)
finalisedList[0] = pkg.EPKPreMap.Name
finalisedList[1] = pkg.EPKPreMap.Architecture
finalisedList[2] = pkg.EPKPreMap.Version.String()
finalisedList[0] = pkg.EPKPreMap.DisplayData.Name
finalisedList[1] = pkg.EPKPreMap.DisplayData.Architecture
finalisedList[2] = pkg.EPKPreMap.DisplayData.Version.String()
if !pkg.IsRemote {
finalisedList[3] = "Local file"
} else {
finalisedList[3] = pkg.Repository.Name
}
finalisedList[4] = humanize.BigIBytes(pkg.EPKPreMap.DecompressedSize)
finalisedList[4] = humanize.BigIBytes(pkg.EPKPreMap.DisplayData.DecompressedSize)
if pkg.IsForced {
finalisedList[5] = "Forced installation"
} else if pkg.EPKPreMap.IsUpgrade {
@ -436,13 +509,16 @@ func main() {
fmt.Println("\nInstalling " + humanize.Comma(int64(len(epkList))) + " packages, of which " + humanize.Comma(int64(dependencies)) + " are dependencies.")
fmt.Println("Total download size: " + humanize.BigIBytes(common.GetTotalSize(epkList)))
fmt.Println("Total installed size: " + humanize.BigIBytes(common.GetTotalInstalledSize(epkList)) + "\n")
response := logger.LogFunc(lib.Log{
Level: "INFO",
Content: "Proceed with installation (y/n)?",
Prompt: true,
PlaySound: true,
})
if strings.ToLower(response) == "y" {
var response string
if !yesMode {
response = logger.LogFunc(lib.Log{
Level: "INFO",
Content: "Proceed with installation (y/n)?",
Prompt: true,
PlaySound: true,
})
}
if strings.ToLower(response) == "y" || yesMode {
// We hide the cursor because it makes the progress bar look weird and other package managers hide
// it during installation. For some reason, it builds suspense. Or it does with me anyway, when
// a program hides the cursor, it makes me think twice than to Ctrl+C it :P
@ -450,10 +526,78 @@ func main() {
fmt.Print("\033[?25l")
// Time to install things.
for _, installPackage := range epkList {
if installPackage.IsRemote {
if !inMemoryMode {
// Set the package stream to the URL.
installPackage.StreamOrBytes.IsURL = true
installPackage.StreamOrBytes.IsRemote = true
installPackage.StreamOrBytes.RepositoryName = installPackage.Repository.Name
installPackage.StreamOrBytes.IsFileStream = false
installPackage.StreamOrBytes.URL = installPackage.Url
} else {
// Download the entire EPK into memory
epkBytes, err := http.Get(installPackage.Url)
if err != nil {
fmt.Println(color.RedString("Failed to download package: " + err.Error()))
os.Exit(1)
}
if epkBytes.StatusCode != 200 {
fmt.Println(color.RedString("Failed to download package: " + epkBytes.Status))
os.Exit(1)
}
// Start streaming the package into a buffer
contentLength := new(big.Int).SetBytes([]byte(epkBytes.Header.Get("Content-Length")))
fmt.Println("\nDownloading package: " + installPackage.EPKPreMap.DisplayData.Name + " (" + humanize.BigIBytes(contentLength) + ")")
var buffer bytes.Buffer
_, err = io.Copy(&lib.ProgressWriter{
Logger: logger,
Total: contentLength,
Writer: &buffer,
}, epkBytes.Body)
if err != nil {
fmt.Println(color.RedString("Failed to read package into memory: " + err.Error()))
os.Exit(1)
}
// Set the progress to 100%
logger.LogFunc(lib.Log{
Level: "PROGRESS",
Progress: big.NewInt(1),
Total: big.NewInt(1),
})
// Close the response body
err = epkBytes.Body.Close()
if err != nil {
fmt.Println(color.HiYellowString("Failed to close response body: " + err.Error() + ", memory leak possible."))
}
fmt.Println("Package downloaded")
// Set the buffer as the bytes
installPackage.StreamOrBytes.Bytes = buffer.Bytes()
installPackage.StreamOrBytes.IsURL = false
installPackage.StreamOrBytes.IsRemote = true
installPackage.StreamOrBytes.RepositoryName = installPackage.Repository.Name
installPackage.StreamOrBytes.IsFileStream = false
}
}
// Map the EPK metadata.
metadata, err, vagueErr := lib.FullyMapMetadata(installPackage.StreamOrBytes,
installPackage.EPKPreMap, common.DefaultGetFingerprintFromDB,
common.DefaultAddFingerprintToDB, logger)
common.DefaultAddFingerprintToDB, func(*lib.Logger) {
logger.LogFunc(lib.Log{
Level: "WARN",
Content: "This server does not support range requests. Please use the -O flag to " +
"enable in memory mode, or contact the server administrator to use a web server " +
"that supports range requests, such as Apache or Nginx. The speed of download " +
"is considerably slowed, as we need to discard bytes since we can only read " +
"sequentially.",
Prompt: false,
})
}, logger)
if err != nil || vagueErr != nil {
common.FullyMapMetadataHandleError(err, vagueErr, logger)
}
@ -464,7 +608,7 @@ func main() {
common.InstallEPKHandleError(tempDir, err, vagueErr, logger)
}
// Done!
fmt.Println("Installed package: " + installPackage.EPKPreMap.Name)
fmt.Println("Installed package: " + installPackage.EPKPreMap.DisplayData.Name)
}
// We show the cursor again because we're done with the progress bar.
fmt.Print("\033[?25h")
@ -486,7 +630,7 @@ func main() {
}
case "repo":
if len(os.Args) < 3 {
fmt.Println("Usage: eon repo (add/remove/list)")
fmt.Println("Usage: eon repo (add/del/list)")
os.Exit(1)
}
@ -508,9 +652,9 @@ func main() {
fmt.Println("Added repository " + repoName + " to the database.")
}
}
case "remove":
case "del":
if len(os.Args) < 4 {
fmt.Println("Usage: eon repo remove <name>")
fmt.Println("Usage: eon repo del <name>")
os.Exit(1)
} else {
err := common.EstablishDBConnection(logger)
@ -539,7 +683,174 @@ func main() {
} else {
fmt.Println("Repositories:")
for _, repo := range repos {
fmt.Println("\n" + repo.Name + ":\n" + " " + repo.Description + "\n URL: " + repo.URL + "\n Owner: " + repo.Owner)
fmt.Println("\n" + repo.Name + ":\n" + "- " + repo.Description + "\n- URL: " + repo.URL + "\n- Owner: " + repo.Owner)
}
fmt.Println()
}
}
case "remove":
if len(os.Args) < 3 {
fmt.Println("Usage: eon remove <package>")
os.Exit(1)
}
err := common.EstablishDBConnection(logger)
if err != nil {
fmt.Println(color.RedString("Failed to establish a connection to the database: " + err.Error()))
os.Exit(1)
}
// Create a map of all installed packages, to minimise the database queries later.
epkMap, decompressedSizeMap, repositoryMap, _, err := common.DefaultListEPKsInDB()
if err != nil {
fmt.Println(color.RedString("Failed to list installed packages: " + err.Error()))
os.Exit(1)
}
// Create a list of packages to remove.
var packageRemoveList []common.RemovePackage
for _, pkg := range os.Args[2:] {
var removePackage common.RemovePackage
_, exists, err := common.DefaultCheckEPKInDB(pkg)
if err != nil {
fmt.Println(color.RedString("Failed to check for package in database: " + err.Error()))
os.Exit(1)
}
if !exists {
fmt.Println(color.RedString("Package not found: " + pkg))
os.Exit(1)
}
// Search to see if it's parent is still installed.
for _, epk := range epkMap {
for _, dep := range epk.Dependencies {
if dep == os.Args[2] {
// First, check if it's in the list of packages to remove.
var found bool
for _, epkName := range os.Args[2:] {
if epkName == epk.Name {
found = true
break
}
}
if !found {
fmt.Println(color.RedString("Package " + pkg + " is a dependency of another package (" + epk.Name + ") and cannot be removed."))
os.Exit(1)
} else {
// It is in the list of packages to remove, we need to set this package's priority higher.
removePackage.Priority++
}
}
}
}
// Add it to the list of packages to remove.
removePackage.Name = pkg
removePackage.DisplayData = epkMap[pkg]
packageRemoveList = append(packageRemoveList, removePackage)
}
if len(packageRemoveList) > 0 {
// First, re-order the packageRemoveList by priority, then alphabetically.
sort.Slice(packageRemoveList, func(i, j int) bool {
if packageRemoveList[i].Priority == packageRemoveList[j].Priority {
return packageRemoveList[i].Name < packageRemoveList[j].Name
}
return packageRemoveList[i].Priority > packageRemoveList[j].Priority
})
// Print the packages that will be removed.
fmt.Println("The following packages will be removed:")
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
fmt.Println(color.RedString("Failed to get terminal width: " + err.Error()))
os.Exit(1)
}
if width < 42 {
fmt.Println(color.RedString("Terminal too small. Minimum required width: 42 characters."))
os.Exit(1)
}
for range width {
fmt.Print("=")
}
fmt.Println()
tableList := []string{"Package", "Architecture", "Version", "Repository", "Installed Size", "Action"}
maxSize := width / 6
for _, item := range tableList {
common.PrintWithEvenPadding(item, maxSize)
}
fmt.Println()
for range width {
fmt.Print("=")
}
fmt.Println()
for _, pkg := range packageRemoveList {
finalisedList := make([]string, 6)
finalisedList[0] = pkg.Name
finalisedList[1] = pkg.DisplayData.Architecture
finalisedList[2] = pkg.DisplayData.Version.String()
finalisedList[3] = repositoryMap[pkg.Name].Name
finalisedList[4] = humanize.BigIBytes(decompressedSizeMap[pkg.Name])
finalisedList[5] = "Remove"
for _, item := range finalisedList {
common.PrintWithEvenPadding(item, maxSize)
}
}
for range width {
fmt.Print("=")
}
fmt.Println("Transaction Summary")
fmt.Println("\nRemoving " + humanize.Comma(int64(len(packageRemoveList))) + " packages.")
space := new(big.Int)
for _, pkg := range packageRemoveList {
space = new(big.Int).Add(space, decompressedSizeMap[pkg.Name])
}
fmt.Println("Total reclaimed space: " + humanize.BigIBytes(space) + "\n")
response := logger.LogFunc(lib.Log{
Level: "INFO",
Content: "Proceed with removal (y/n)?",
Prompt: true,
})
if strings.ToLower(response) == "y" {
for _, pkg := range packageRemoveList {
err, vagueErr := lib.RemoveEPK(pkg.Name, common.DefaultRemoveEPKFromDB, common.DefaultGetEPKRemoveInfoFromDB, logger)
if err != nil || vagueErr != nil {
common.RemoveEPKHandleError(err, vagueErr, logger)
fmt.Println(color.RedString("Failed to remove package: " + vagueErr.Error() + err.Error()))
}
fmt.Println("Removed package: " + pkg.Name)
}
} else {
fmt.Println("Removal cancelled.")
os.Exit(1)
}
}
case "list":
if len(os.Args) < 3 {
fmt.Println("Usage: eon list (remote/local)")
os.Exit(1)
}
err := common.EstablishDBConnection(logger)
if err != nil {
fmt.Println(color.RedString("Failed to establish a connection to the database: " + err.Error()))
os.Exit(1)
}
switch os.Args[2] {
case "remote":
remoteEpkList, err := common.DefaultListRemotePackagesInDB()
if err != nil {
fmt.Println(color.RedString("Failed to list remote packages: " + err.Error()))
os.Exit(1)
}
if len(remoteEpkList) == 0 {
fmt.Println("No remote packages.")
} else {
fmt.Println("Remote packages:")
for _, epk := range remoteEpkList {
fmt.Println("\n" + epk.Name + ":\n" +
"- " + epk.Description +
"\n- Author: " + epk.Author +
"\n- Size to download: " + humanize.Bytes(uint64(epk.CompressedSize)) +
"\n- Version: " + epk.Version.String() +
"\n- Architecture: " + epk.Architecture +
"\n- Repository: " + epk.Repository.Name)
}
fmt.Println()
}

View file

@ -1,25 +1,27 @@
package common
import (
"encoding/binary"
"eon/lib"
"math"
"net/http"
"net/url"
"bufio"
"bytes"
"errors"
"fmt"
"math"
"os"
"plugin"
"regexp"
"sort"
"strconv"
"strings"
"time"
"crypto/ed25519"
"database/sql"
"encoding/binary"
"math/big"
"net/http"
"net/url"
"golang.org/x/term"
@ -39,6 +41,12 @@ type InstallPackage struct {
Repository lib.Repository
}
type RemovePackage struct {
Name string
Priority int
DisplayData lib.DisplayData
}
type PluginInfo struct {
Name string
HasErrHandler bool
@ -53,7 +61,7 @@ type Plugin struct {
}
var conn *sql.DB
var dbVersion = semver.MustParse("1.0.0-beta.3")
var dbVersion = semver.MustParse("1.0.0-beta.4")
var DefaultLogger = lib.Logger{
LogFunc: func(log lib.Log) string {
@ -83,7 +91,7 @@ var DefaultLogger = lib.Logger{
// Get the terminal width so we can calculate the width of the progress bar.
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
fmt.Println(color.RedString("Failed to get terminal width: " + err.Error()))
fmt.Println(color.RedString("Could not get terminal width: " + err.Error()))
os.Exit(1)
}
// Calculate the percentage in text form.
@ -123,13 +131,13 @@ var DefaultLogger = lib.Logger{
}
if log.Prompt {
fmt.Print(": ")
var userInput string
_, err := fmt.Scanln(&userInput)
reader := bufio.NewReader(os.Stdin)
userInput, err := reader.ReadString('\n')
if err != nil {
fmt.Println(color.RedString("Failed to read input: " + err.Error()))
fmt.Println(color.RedString("[FATAL]"), "Could not read user input:", err)
os.Exit(1)
} else {
return userInput
return userInput[:len(userInput)-1]
}
}
return ""
@ -185,45 +193,44 @@ var TimeMagnitudes = []humanize.RelTimeMagnitude{
// End of Expat / MIT licensed code
}
func HandleDependencies(previousDeps int, targetEPK InstallPackage, parentPriority int, epkList []lib.RemoteEPK, ListRemotePackagesInDB func() ([]lib.RemoteEPK, error), InstallPackageList *[]InstallPackage, logger *lib.Logger) (int, error) {
func HandleDependencies(previousDeps int, targetEPK InstallPackage, parentPriority int, epkList []lib.RemoteEPK, ListRemotePackagesInDB func() ([]lib.RemoteEPK, error), InstallPackageList []InstallPackage, previousPackages *[]string, logger *lib.Logger) ([]InstallPackage, int, error) {
// Iterate through the dependencies of the target EPK.
dependencyLoop:
for _, dependency := range targetEPK.EPKPreMap.Dependencies {
for _, dependency := range targetEPK.EPKPreMap.DisplayData.Dependencies {
// Check if the dependency is already in the list of EPKs to install.
for iterator, epk := range *InstallPackageList {
if epk.EPKPreMap.Name == dependency {
for iterator, epk := range InstallPackageList {
if epk.EPKPreMap.DisplayData.Name == dependency {
// The dependency is already in the list of EPKs to install, check for its dependencies.
if len(epk.EPKPreMap.Dependencies) == 0 || epk.EPKPreMap.Dependencies == nil {
if len(epk.EPKPreMap.DisplayData.Dependencies) == 0 || epk.EPKPreMap.DisplayData.Dependencies == nil {
// All dependencies are handled - change the priority and continue with the next dependency.
epk.Priority = parentPriority + 1
currentInstallPackageList := *InstallPackageList
currentInstallPackageList[iterator] = epk
InstallPackageList = &currentInstallPackageList
InstallPackageList[iterator] = epk
continue dependencyLoop
} else {
// Check if it's a circular dependency.
for _, epk := range *InstallPackageList {
if epk.EPKPreMap.Name == targetEPK.EPKPreMap.Name {
for _, epk := range *previousPackages {
if epk == targetEPK.EPKPreMap.DisplayData.Name {
// We have a circular dependency. Crash immediately.
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Circular dependency detected: " + targetEPK.EPKPreMap.Name + " -> " + dependency + " -> " + targetEPK.EPKPreMap.Name,
Content: "Circular dependency detected: " + targetEPK.EPKPreMap.DisplayData.Name + " -> " + dependency + " -> " + targetEPK.EPKPreMap.DisplayData.Name,
Prompt: false,
})
}
}
// Add the dependency to the list of previous packages.
*previousPackages = append(*previousPackages, targetEPK.EPKPreMap.DisplayData.Name)
// Recursively handle dependencies.
addedDeps, err := HandleDependencies(previousDeps, epk, parentPriority+1, epkList, ListRemotePackagesInDB, InstallPackageList, logger)
installedPackage, addedDeps, err := HandleDependencies(previousDeps, epk, parentPriority+1, epkList, ListRemotePackagesInDB, InstallPackageList, previousPackages, logger)
InstallPackageList = installedPackage
if err != nil {
return 0, err
return nil, 0, err
} else {
// Add the dependencies to the total number of dependencies.
previousDeps += addedDeps
// All dependencies are now handled - change the priority and continue with the next dependency.
epk.Priority = parentPriority + 1
currentInstallPackageList := *InstallPackageList
currentInstallPackageList[iterator] = epk
InstallPackageList = &currentInstallPackageList
InstallPackageList[iterator] = epk
continue dependencyLoop
}
}
@ -235,14 +242,14 @@ dependencyLoop:
var err error
epkList, err = ListRemotePackagesInDB()
if err != nil {
return 0, err
return nil, 0, err
}
}
// Check if we already have the EPK installed.
version, exists, err := DefaultCheckEPKInDB(dependency)
if err != nil {
return 0, err
return nil, 0, err
}
var remoteEPK lib.RemoteEPK
@ -270,7 +277,7 @@ dependencyLoop:
}
// If the dependency doesn't exist, crash.
if !dependencyExists {
return 0, errors.New("dependency " + dependency + " does not exist")
return nil, 0, errors.New("dependency " + dependency + " does not exist")
}
// Increase the dependency's priority.
epkEntry.Priority = parentPriority + 1
@ -279,7 +286,7 @@ dependencyLoop:
if err != nil {
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to join URL path: " + err.Error(),
Content: "Could not join URL path: " + err.Error(),
Prompt: false,
})
}
@ -289,7 +296,7 @@ dependencyLoop:
// Map the EPKs display data.
epkPreMap, err, vagueErr := lib.PreMapRemoteEPK(remoteEPK, logger)
if err != nil || vagueErr != nil {
return 0, err
return nil, 0, err
}
// Set the EPKs display data.
epkEntry.EPKPreMap = &epkPreMap
@ -304,40 +311,42 @@ dependencyLoop:
// Check if the dependency has dependencies, and if so, recursively handle them.
if !(len(remoteEPK.Dependencies) == 0 || remoteEPK.Dependencies == nil) {
// Check if it's a circular dependency.
for _, epk := range *InstallPackageList {
if epk.EPKPreMap.Name == targetEPK.EPKPreMap.Name {
for _, epk := range *previousPackages {
if epk == targetEPK.EPKPreMap.DisplayData.Name {
// We have a circular dependency. Crash immediately.
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Circular dependency detected: " + targetEPK.EPKPreMap.Name + " -> " + dependency + " -> " + targetEPK.EPKPreMap.Name,
Content: "Circular dependency detected: " + targetEPK.EPKPreMap.DisplayData.Name + " -> " + dependency + " -> " + targetEPK.EPKPreMap.DisplayData.Name,
Prompt: false,
})
}
}
// Add the dependency to the list of previous packages.
*previousPackages = append(*previousPackages, epkEntry.EPKPreMap.DisplayData.Name)
// Recursively handle dependencies.
addedDeps, err := HandleDependencies(previousDeps, epkEntry, epkEntry.Priority+1, epkList, ListRemotePackagesInDB, InstallPackageList, logger)
installPackages, addedDeps, err := HandleDependencies(previousDeps, epkEntry, epkEntry.Priority+1, epkList, ListRemotePackagesInDB, InstallPackageList, previousPackages, logger)
InstallPackageList = installPackages
if err != nil {
return 0, err
return nil, 0, err
}
// Add the dependencies to the total number of dependencies.
previousDeps += addedDeps
}
// All dependencies are now handled - continue with the next dependency.
currentInstallPackageList := append(*InstallPackageList, epkEntry)
InstallPackageList = &currentInstallPackageList
InstallPackageList = append(InstallPackageList, epkEntry)
previousDeps++
continue
}
// If we reach this point, all dependencies have been handled.
return previousDeps, nil
return InstallPackageList, previousDeps, nil
}
func GetTotalSize(InstallPackageList []InstallPackage) *big.Int {
totalSize := new(big.Int)
for _, epk := range InstallPackageList {
totalSize.Add(totalSize, big.NewInt(epk.EPKPreMap.Size))
totalSize.Add(totalSize, big.NewInt(epk.EPKPreMap.DisplayData.Size))
}
return totalSize
}
@ -346,7 +355,7 @@ func GetTotalInstalledSize(InstallPackageList []InstallPackage) *big.Int {
totalSize := new(big.Int)
for _, epk := range InstallPackageList {
if !epk.IsRemote {
totalSize.Add(totalSize, epk.EPKPreMap.DecompressedSize)
totalSize.Add(totalSize, epk.EPKPreMap.DisplayData.DecompressedSize)
}
}
return totalSize
@ -492,7 +501,7 @@ func InitDB(conn *sql.DB) error {
// Huge query moment. This is way too big to read comfortably, but too bad! It breaks the Jetbrains SQL formatter if
// I break it into multiple lines.
_, err = conn.Exec("CREATE TABLE packages (name TEXT NOT NULL UNIQUE, description TEXT NOT NULL, longDescription TEXT NOT NULL, version TEXT NOT NULL, author TEXT NOT NULL, license TEXT NOT NULL, architecture TEXT NOT NULL, size INTEGER NOT NULL, dependencies TEXT NOT NULL, removeScript TEXT NOT NULL, hasRemoveScript BOOLEAN NOT NULL, isDependency BOOLEAN NOT NULL DEFAULT false, repository TEXT)")
_, err = conn.Exec("CREATE TABLE packages (name TEXT NOT NULL UNIQUE, description TEXT NOT NULL, longDescription TEXT NOT NULL, version TEXT NOT NULL, author TEXT NOT NULL, license TEXT NOT NULL, architecture TEXT NOT NULL, size INTEGER NOT NULL, dependencies TEXT NOT NULL, removeScript TEXT NOT NULL, hasRemoveScript BOOLEAN NOT NULL, isDependency BOOLEAN NOT NULL DEFAULT false, repository TEXT, installedPaths TEXT)")
if err != nil {
return err
}
@ -590,7 +599,7 @@ func EstablishDBConnection(logger *lib.Logger) error {
} else {
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The database is corrupted and cannot be used. Please reset the database.",
Content: "The database is corrupted and could not be used. Please reset the database.",
Prompt: false,
})
os.Exit(1)
@ -598,7 +607,7 @@ func EstablishDBConnection(logger *lib.Logger) error {
} else {
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The database is corrupted and cannot be used. Please reset the database.",
Content: "The database is corrupted and could not be used. Please reset the database.",
Prompt: false,
})
os.Exit(1)
@ -645,7 +654,7 @@ func EstablishDBConnection(logger *lib.Logger) error {
return nil
}
func DefaultAddEPKToDB(metadata *lib.Metadata, removeScript []byte, dependency bool, hasRemoveScript bool, size int64, repository ...string) error {
func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, removeScript []byte, dependency bool, hasRemoveScript bool, size int64, repository ...string) error {
// If it already exists, delete it. This may happen in a force-install scenario.
_, err := conn.Exec("DELETE FROM packages WHERE name = ?", metadata.Name)
if err != nil {
@ -663,6 +672,13 @@ func DefaultAddEPKToDB(metadata *lib.Metadata, removeScript []byte, dependency b
dependencies = "[]"
}
var installedPathsString string
if len(installedPaths) > 0 {
installedPathsString = "[" + strings.Join(installedPaths, ", ") + "]"
} else {
installedPathsString = "[]"
}
// Another fat unreadable line so Jetbrains doesn't break the SQL formatter. Too bad!
// But seriously though why doesn't Jetbrains support this? It's literally their own IDE which tells me to not make
// super-long lines, but then doesn't support it.
@ -671,14 +687,15 @@ func DefaultAddEPKToDB(metadata *lib.Metadata, removeScript []byte, dependency b
// Not that I'm complaining or anything.
// - Arzumify
if len(repository) > 0 {
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
metadata.Name, metadata.Description, metadata.LongDescription, metadata.Version.String(), metadata.Author,
metadata.License, metadata.Architecture, size, dependencies, string(removeScript), hasRemoveScript, dependency,
repository[0])
repository[0], installedPathsString)
} else {
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, installedPaths) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
metadata.Name, metadata.Description, metadata.LongDescription, metadata.Version.String(), metadata.Author,
metadata.License, metadata.Architecture, size, dependencies, string(removeScript), hasRemoveScript, dependency)
metadata.License, metadata.Architecture, size, dependencies, string(removeScript), hasRemoveScript, dependency,
installedPathsString)
}
if err != nil {
return err
@ -712,32 +729,111 @@ func DefaultCheckEPKInDB(name string) (*semver.Version, bool, error) {
return version, true, nil
}
func DefaultGetEPKFromDB(name string) (lib.Metadata, string, bool, bool, int64, error) {
func DefaultGetEPKFromDB(name string) (lib.Metadata, string, bool, bool, int64, string, []string, error) {
var metadata lib.Metadata
var removeScript string
var dependency bool
var versionString string
var dependencies string
var hasRemoveScript bool
var repository string
var installedPaths string
var size int64
err := conn.QueryRow("SELECT name, description, longDescription, version, author, license, architecture, size, "+
"dependencies, removeScript, hasRemoveScript, isDependency FROM packages WHERE name = ?", name).Scan(
&metadata.Name, &metadata.Description, &metadata.LongDescription, &versionString, &metadata.Author,
err := conn.QueryRow("SELECT description, longDescription, version, author, license, architecture, size, "+
"dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths FROM packages WHERE name = ?",
name).Scan(&metadata.Description, &metadata.LongDescription, &versionString, &metadata.Author,
&metadata.License, &metadata.Architecture, &size, &dependencies, &removeScript, &hasRemoveScript,
&dependency)
&dependency, &repository, &installedPaths)
if err != nil {
return lib.Metadata{}, "", false, false, 0, err
return lib.Metadata{}, "", false, false, 0, "", nil, err
}
// This is the world's most basic JSON unmarshaller :P
// - Arzumify
metadata.Dependencies = strings.Split(strings.TrimSuffix(strings.TrimPrefix(dependencies, "["), "]"), ", ")
version, err := semver.NewVersion(versionString)
if err != nil {
return lib.Metadata{}, "", false, false, 0, err
return lib.Metadata{}, "", false, false, 0, "", nil, err
}
// Also unmarshal the installed paths
var installedPathsSlice []string
installedPathsSlice = strings.Split(strings.TrimSuffix(strings.TrimPrefix(installedPaths, "["), "]"), ", ")
// For some reason NewVersion returns a pointer
metadata.Version = *version
return metadata, removeScript, dependency, hasRemoveScript, size, nil
return metadata, removeScript, dependency, hasRemoveScript, size, repository, installedPathsSlice, nil
}
func DefaultRemoveEPKFromDB(name string) error {
_, err := conn.Exec("DELETE FROM packages WHERE name = ?", name)
if err != nil {
return err
}
return nil
}
func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map[string]lib.Repository, map[string]int64, error) {
rows, err := conn.Query("SELECT name, description, version, author, architecture, size, dependencies, repository FROM packages")
if err != nil {
return nil, nil, nil, nil, err
}
repositoryMap := make(map[string]lib.Repository)
repoNameToRepo := make(map[string]lib.Repository)
metadataMap := make(map[string]lib.DisplayData)
sizes := make(map[string]*big.Int)
compressedSizes := make(map[string]int64)
for rows.Next() {
var metadata lib.DisplayData
var size int64
var dependencies string
var repository string
var version string
err := rows.Scan(&metadata.Name, &metadata.Description, &version,
&metadata.Author, &metadata.Architecture, &size, &dependencies, &repository)
if err != nil {
return nil, nil, nil, nil, err
}
semVer, err := semver.NewVersion(version)
if err != nil {
return nil, nil, nil, nil, err
}
// Stupid pointer
metadata.Version = *semVer
metadata.Dependencies = strings.Split(strings.TrimSuffix(strings.TrimPrefix(dependencies, "["), "]"), ", ")
metadataMap[metadata.Name] = metadata
sizes[metadata.Name] = big.NewInt(size)
compressedSizes[metadata.Name] = size
// Check if the repository is in the repoNameToRepo map
_, ok := repoNameToRepo[repository]
if !ok {
// If it's not, find the repository and add it to the map
var repo lib.Repository
err := conn.QueryRow("SELECT url, owner, description FROM repositories WHERE name = ?", repository).Scan(&repo.URL, &repo.Owner, &repo.Description)
if err != nil {
return nil, nil, nil, nil, err
}
repositoryMap[repository] = repo
}
// Add the repository to the repository map
repositoryMap[metadata.Name] = repoNameToRepo[repository]
}
return metadataMap, sizes, repositoryMap, compressedSizes, nil
}
func DefaultGetEPKRemoveInfoFromDB(name string) (string, []string, error) {
var removeScript string
var installedPaths string
err := conn.QueryRow("SELECT removeScript, installedPaths FROM packages WHERE name = ?", name).Scan(&removeScript, &installedPaths)
if err != nil {
return "", nil, err
}
// Unmarshal the installed paths
var installedPathsSlice []string
installedPathsSlice = strings.Split(strings.TrimSuffix(strings.TrimPrefix(installedPaths, "["), "]"), ", ")
return removeScript, installedPathsSlice, nil
}
func DefaultAddFingerprintToDB(fingerprint []byte, owner string, replace bool) error {
@ -781,11 +877,12 @@ func DefaultGetFingerprintFromDB(fingerprint []byte, author string) (bool, bool,
func DefaultAddRepositoryToDB(repository lib.Repository, forceReplace bool) error {
if forceReplace {
// Delete the repository if it already exists. This may happen in a force-install scenario.
_, err := conn.Exec("DELETE FROM repositories WHERE name = ?", repository.Name)
_, err := conn.Exec("DELETE FROM repositories WHERE name = ? OR url = ?", repository.Name, repository.URL)
if err != nil {
return err
}
}
_, err := conn.Exec("INSERT INTO repositories (url, name, owner, description) VALUES (?, ?, ?, ?)",
repository.URL, repository.Name, repository.Owner, repository.Description)
if err != nil {
@ -833,6 +930,7 @@ func DefaultListRepositoriesInDB() ([]lib.Repository, error) {
}
repositories = append(repositories, lib.Repository{Name: name, URL: repoUrl, Owner: owner, Description: description})
}
return repositories, nil
}
@ -876,7 +974,7 @@ func DefaultRemoveRemotePackageFromDB(name string) error {
}
func DefaultListRemotePackagesInDB() ([]lib.RemoteEPK, error) {
rows, err := conn.Query("SELECT name, author, description, version, architecture, size, dependencies, path, arch, hash, repository FROM remotePackages")
rows, err := conn.Query("SELECT name, author, description, version, architecture, size, dependencies, path, arch, hash, repository FROM remotePackages ORDER BY version")
if err != nil {
return []lib.RemoteEPK{}, err
}
@ -923,6 +1021,11 @@ func DefaultListRemotePackagesInDB() ([]lib.RemoteEPK, error) {
})
}
// Re-sort remotePackages by version, latest first - this stops the package manager from installing older versions.
sort.Slice(remotePackages, func(i, j int) bool {
return remotePackages[i].Version.GreaterThan(&remotePackages[j].Version)
})
return remotePackages, nil
}
@ -1029,34 +1132,94 @@ func RefreshPackageList(listRepositoriesInDB func() ([]lib.Repository, error), a
// PreMapEPKHandleError handles errors that occur during the mapping of an EPKs display data.
func PreMapEPKHandleError(err error, vagueErr error, logger *lib.Logger) {
switch {
case errors.Is(vagueErr, lib.ErrPreMapEPKFailedToReadError):
case errors.Is(vagueErr, lib.ErrPreMapEPKCouldNotRead):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to read file: " + err.Error(),
Content: "Could not read file: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapEPKNotEPKError):
case errors.Is(vagueErr, lib.ErrPreMapEPKHasNetworkStream):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Network streams are not supported: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapEPKHasNotGotEPKMagic):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The specified file is not an EPK.",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapEPKInvalidEndianError):
case errors.Is(vagueErr, lib.ErrPreMapEPKHasInvalidEndian):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The specified file is corrupted or invalid: invalid endian",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapEPKCouldNotParseJSONError):
case errors.Is(vagueErr, lib.ErrPreMapEPKCouldNotMapJSON):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to parse metadata JSON: " + err.Error(),
Content: "Could not map metadata JSON: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapEPKCouldNotMapJSONError):
}
}
// PreMapRemoteEPKHandleError handles errors that occur during the mapping of a remote EPKs display data.
func PreMapRemoteEPKHandleError(err error, vagueErr error, logger *lib.Logger) {
switch {
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKCouldNotCreateURL):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to map metadata JSON: " + err.Error(),
Content: "Could not create URL: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKCouldNotCreateRequest):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not create request: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKCouldNotSendRequest):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not send request: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKCouldNotRead):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not read EPK: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKCouldNotCloseConnection):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not close connection: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKUnexpectedStatusCode):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Unexpected status code: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapEPKHasNotGotEPKMagic):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The specified file is not an EPK.",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKInvalidEndian):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The specified file is corrupted or invalid: invalid endian",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrPreMapRemoteEPKCouldNotMapJSON):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not map metadata JSON: " + err.Error(),
Prompt: false,
})
}
@ -1065,40 +1228,40 @@ func PreMapEPKHandleError(err error, vagueErr error, logger *lib.Logger) {
// FullyMapMetadataHandleError handles errors that occur during the mapping of an EPK file.
func FullyMapMetadataHandleError(err error, vagueErr error, logger *lib.Logger) {
switch {
case errors.Is(vagueErr, lib.ErrFullyMapMetadataFailedToReadError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotRead):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to read file: " + err.Error(),
Content: "Could not read file: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrFullyMapMetadataFailedToJumpError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotJump):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to jump to metadata: " + err.Error(),
Content: "Could not jump to metadata: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrFullyMapMetadataFailedToAddFingerprintError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotAddFingerprint):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to add fingerprint to database: " + err.Error(),
Content: "Could not add fingerprint to database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrFullyMapMetadataFailedToGetFingerprintError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotGetFingerprint):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to get fingerprint from database: " + err.Error(),
Content: "Could not get fingerprint from database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrFullyMapMetadataInvalidSignatureError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataHasInvalidSignature):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "The specified file is corrupted or invalid: signature mismatch",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotMapJSONError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotMapJSON):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to map metadata JSON: " + err.Error(),
Content: "Could not map metadata JSON: " + err.Error(),
Prompt: false,
})
}
@ -1108,76 +1271,76 @@ func FullyMapMetadataHandleError(err error, vagueErr error, logger *lib.Logger)
func InstallEPKHandleError(tempDir string, err error, vagueErr error, logger *lib.Logger) {
doNotRemoveTempDir := false
switch {
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateTempDirError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateTempDir):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to create temporary directory: " + err.Error(),
Content: "Could not create temporary directory: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateZStandardReaderError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateZStandardReader):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to create ZStandard reader: " + err.Error(),
Content: "Could not create ZStandard reader: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotDecompressTarArchiveError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotDecompressTarArchive):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to decompress tar archive: " + err.Error(),
Content: "Could not decompress tar archive: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateDirError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateDir):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to create directory: " + err.Error(),
Content: "Could not create directory: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotStatDirError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotStatDir):
logger.LogFunc(lib.Log{
Level: "ERROR",
Content: "Could not get file information about directory: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotStatFileError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotStatFile):
logger.LogFunc(lib.Log{
Level: "ERROR",
Content: "Could not get file information about file: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateFileError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCreateFile):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to create file: " + err.Error(),
Content: "Could not create file: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCloseTarReaderError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotCloseTarReader):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to close tar reader: " + err.Error(),
Content: "Could not close tar reader: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotStatHookError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotStatHook):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not get file information about hook: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotRunHookError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotRunHook):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to run hook: " + err.Error(),
Content: "Could not run hook: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotAddEPKToDBError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotAddEPKToDB):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to add EPK to database: " + err.Error(),
Content: "Could not add EPK to database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotRemoveTempDirError):
case errors.Is(vagueErr, lib.ErrInstallEPKCouldNotRemoveTempDir):
logger.LogFunc(lib.Log{
Level: "CRITICAL",
Content: "Failed to remove temporary directory: " + err.Error() + ", please remove the directory " + tempDir + " manually",
Content: "Could not remove temporary directory: " + err.Error() + ", please remove the directory " + tempDir + " manually",
Prompt: false,
})
doNotRemoveTempDir = true
@ -1187,7 +1350,7 @@ func InstallEPKHandleError(tempDir string, err error, vagueErr error, logger *li
if err != nil {
logger.LogFunc(lib.Log{
Level: "CRITICAL",
Content: "Failed to remove temporary directory: " + err.Error() + ", please remove the directory " + tempDir + " manually",
Content: "Could not remove temporary directory: " + err.Error() + ", please remove the directory " + tempDir + " manually",
Prompt: false,
})
}
@ -1196,94 +1359,82 @@ func InstallEPKHandleError(tempDir string, err error, vagueErr error, logger *li
func AddRepositoryHandleError(err error, vagueErr error, logger *lib.Logger) {
switch {
case errors.Is(vagueErr, lib.ErrAddRepositoryCannotCreateRequestError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotCreateRequest):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to create request: " + err.Error(),
Content: "Could not create request: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryCannotSendRequestError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotSendRequest):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to send request: " + err.Error(),
Content: "Could not send request: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryUnexpectedStatusCodeError):
case errors.Is(vagueErr, lib.ErrAddRepositoryHasUnexpectedStatusCode):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Unexpected status code: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryCannotReadResponseError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotReadResponse):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to read response: " + err.Error(),
Content: "Could not read response: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryInvalidMagicError):
case errors.Is(vagueErr, lib.ErrAddRepositoryHasInvalidMagic):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Invalid magic: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryCannotHashError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotHash):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to copy file to hash: " + err.Error(),
Content: "Could not copy file to hash: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryUnmarshalMetadataError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotUnmarshalMetadata):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to unmarshal metadata: " + err.Error(),
Content: "Could not unmarshal metadata: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrFullyMapMetadataFailedToGetFingerprintError):
case errors.Is(vagueErr, lib.ErrFullyMapMetadataCouldNotGetFingerprint):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to get fingerprint from database: " + err.Error(),
Content: "Could not get fingerprint from database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryFailedToAddFingerprintError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotAddFingerprint):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to add fingerprint to database: " + err.Error(),
Content: "Could not add fingerprint to database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryInvalidMetadataError):
case errors.Is(vagueErr, lib.ErrAddRepositoryHasInvalidMetadata):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Invalid metadata: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryCannotCreateDirError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotAddPackage):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to create repository directory: " + err.Error(),
Content: "Could not add package to database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryCannotStatDirError):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to get file information about repository directory: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryFailedToAddPackageError):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to add package to database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryRepositoryAlreadyExistsError):
case errors.Is(vagueErr, lib.ErrAddRepositoryHasRepositoryExists):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Repository already exists",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrAddRepositoryFailedToAddRepositoryError):
case errors.Is(vagueErr, lib.ErrAddRepositoryCouldNotAddRepository):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to add repository to database: " + err.Error(),
Content: "Could not add repository to database: " + err.Error(),
Prompt: false,
})
@ -1292,28 +1443,70 @@ func AddRepositoryHandleError(err error, vagueErr error, logger *lib.Logger) {
func RemoveRepositoryHandleError(err error, vagueErr error, logger *lib.Logger) {
switch {
case errors.Is(vagueErr, lib.ErrRemoveRepositoryDoesNotExistError):
case errors.Is(vagueErr, lib.ErrRemoveRepositoryDoesNotExist):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Repository does not exist",
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveRepositoryCannotFindRepositoryError):
case errors.Is(vagueErr, lib.ErrRemoveRepositoryCouldNotFindRepository):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to get file information about repository: " + err.Error(),
Content: "Could not get file information about repository: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveRepositoryCannotRemoveRepositoryError):
case errors.Is(vagueErr, lib.ErrRemoveRepositoryCouldNotRemoveRepository):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to remove repository files: " + err.Error(),
Content: "Could not remove repository files: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveRepositoryFailedToRemoveRepositoryFromDBError):
case errors.Is(vagueErr, lib.ErrRemoveRepositoryCouldNotRemoveRepositoryFromDB):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Failed to remove repository from database: " + err.Error(),
Content: "Could not remove repository from database: " + err.Error(),
Prompt: false,
})
}
}
// RemoveEPKHandleError handles errors that occur during the removal of an EPK.
func RemoveEPKHandleError(err error, vagueErr error, logger *lib.Logger) {
switch {
case errors.Is(vagueErr, lib.ErrRemoveEPKCouldNotFindEPK):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not get EPK from database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveEPKCouldNotCreateTempFile):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not create temporary file: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveEPKCouldNotWriteTempFile):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not write to temporary file: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveEPKCouldNotRunRemoveHook):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not run remove hook: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveEPKCouldNotRemoveEPKFromDB):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not remove EPK from database: " + err.Error(),
Prompt: false,
})
case errors.Is(vagueErr, lib.ErrRemoveEPKCouldNotRemoveFiles):
logger.LogFunc(lib.Log{
Level: "FATAL",
Content: "Could not remove files: " + err.Error(),
Prompt: false,
})
}

File diff suppressed because it is too large Load diff