We are production ready!! Yayy!!! (I finished everything)

This commit is contained in:
Arzumify 2024-09-13 20:16:48 +01:00
parent 6fcd316f39
commit f903fe44dd
4 changed files with 306 additions and 21 deletions

BIN
cmd/cmd

Binary file not shown.

View file

@ -64,7 +64,7 @@ func main() {
fmt.Println("Removes unused dependencies.") fmt.Println("Removes unused dependencies.")
case "repo": case "repo":
fmt.Println("Usage: eon repo (add/del/list)") fmt.Println("Usage: eon repo (add/del/list)")
fmt.Println("- add <url>: adds a repository.") fmt.Println("- add <packageUrl>: adds a repository.")
fmt.Println("- del <name>: removes a repository.") fmt.Println("- del <name>: removes a repository.")
fmt.Println("- list: lists repositories.") fmt.Println("- list: lists repositories.")
case "help": case "help":
@ -197,6 +197,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
preMap.DisplayData.IsDependency = false
var installPackage common.InstallPackage var installPackage common.InstallPackage
installPackage.EPKPreMap = &preMap installPackage.EPKPreMap = &preMap
installPackage.Url = "" installPackage.Url = ""
@ -321,6 +323,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
preMap.DisplayData.IsDependency = false
// Map the data we have // Map the data we have
epkEntry.Priority = 0 epkEntry.Priority = 0
epkEntry.EPKPreMap = &preMap epkEntry.EPKPreMap = &preMap
@ -640,7 +644,7 @@ func main() {
switch os.Args[2] { switch os.Args[2] {
case "add": case "add":
if len(os.Args) < 4 { if len(os.Args) < 4 {
fmt.Println("Usage: eon repo add <url>") fmt.Println("Usage: eon repo add <packageUrl>")
os.Exit(1) os.Exit(1)
} else { } else {
err := common.EstablishDBConnection(logger) err := common.EstablishDBConnection(logger)
@ -930,6 +934,276 @@ func main() {
} }
} }
} }
case "info":
if len(os.Args) < 3 {
fmt.Println("Usage: eon info <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)
}
err = common.RefreshPackageList(common.DefaultListRepositoriesInDB, common.DefaultAddRemotePackageToDB,
common.DefaultGetFingerprintFromDB, common.DefaultAddFingerprintToDB, common.DefaultCheckRepositoryInDB,
common.DefaultAddRepositoryToDB, common.DefaultListRemotePackagesInDB, common.DefaultRemoveRemotePackageFromDB,
logger)
if err != nil {
fmt.Println(color.RedString("Failed to refresh package list: " + err.Error()))
}
remoteEpks, err := common.DefaultListRemotePackagesInDB()
if err != nil {
fmt.Println(color.RedString("Failed to list installed packages: " + err.Error()))
os.Exit(1)
}
var remoteEpk lib.RemoteEPK
for _, epk := range remoteEpks {
if epk.Name == os.Args[2] {
remoteEpk = epk
break
}
}
if remoteEpk.Name == "" {
fmt.Println(color.RedString("Package not found: " + os.Args[2]))
os.Exit(1)
}
epkPreMap, err, vagueErr := lib.PreMapRemoteEPK(remoteEpk, logger)
if err != nil || vagueErr != nil {
common.PreMapRemoteEPKHandleError(err, vagueErr, logger)
}
packageUrl, err := url.JoinPath(remoteEpk.Repository.URL, remoteEpk.Path)
if err != nil {
fmt.Println(color.RedString("Failed to join URL: " + err.Error()))
os.Exit(1)
}
metadata, err, vagueErr := lib.FullyMapMetadata(lib.StreamOrBytes{
IsURL: true,
URL: packageUrl,
}, &epkPreMap, common.DefaultGetFingerprintFromDB, 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)
}
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 < 11 {
fmt.Println(color.RedString("Terminal too small. Minimum required width: 11 characters."))
os.Exit(1)
}
fmt.Println()
for range width {
fmt.Print("=")
}
common.PrintWithEvenPadding("Information", width/2)
common.PrintWithEvenPadding("Content", width/2)
for range width {
fmt.Print("=")
}
common.PrintWithEvenPadding("Name", width/2)
common.PrintWithEvenPadding(epkPreMap.DisplayData.Name, width/2)
common.PrintWithEvenPadding("Version", width/2)
common.PrintWithEvenPadding(metadata.Version.String(), width/2)
common.PrintWithEvenPadding("Description", width/2)
common.PrintWithEvenPadding(metadata.Description, width/2)
common.PrintWithEvenPadding("License", width/2)
common.PrintWithEvenPadding(metadata.License, width/2)
common.PrintWithEvenPadding("Architecture", width/2)
common.PrintWithEvenPadding(metadata.Architecture, width/2)
common.PrintWithEvenPadding("Installed Size", width/2)
common.PrintWithEvenPadding(humanize.BigIBytes(metadata.DecompressedSize), width/2)
common.PrintWithEvenPadding("Download Size", width/2)
common.PrintWithEvenPadding(humanize.Bytes(uint64(metadata.Size)), width/2)
common.PrintWithEvenPadding("Repository", width/2)
common.PrintWithEvenPadding(remoteEpk.Repository.Name, width/2)
common.PrintWithEvenPadding("Dependencies", width/2)
if len(metadata.Dependencies) == 0 {
common.PrintWithEvenPadding("None", width/2)
} else {
common.PrintWithEvenPadding(strings.Join(metadata.Dependencies, ", "), width/2)
}
// We don't print the long description - it's meant for GUIs.
for range width {
fmt.Print("=")
}
case "clean":
err := common.EstablishDBConnection(logger)
if err != nil {
fmt.Println(color.RedString("Failed to establish a connection to the database: " + err.Error()))
os.Exit(1)
}
packages, _, repositoryMap, _, err := common.DefaultListEPKsInDB()
if err != nil {
fmt.Println(color.RedString("Failed to list installed packages: " + err.Error()))
os.Exit(1)
}
if len(packages) == 0 {
fmt.Println("No packages to clean.")
os.Exit(0)
} else {
var removeList []common.RemovePackage
for _, pkg := range packages {
// Check if it's a dependency of another package.
if pkg.IsDependency {
// Add it to list of candidates for removal.
var removePackage common.RemovePackage
removePackage.Name = pkg.Name
removePackage.DisplayData = pkg
removeList = append(removeList, removePackage)
}
}
for _, pkg := range removeList {
// Check if it's parent is still installed.
for _, epk := range packages {
for _, dep := range epk.Dependencies {
if dep == pkg.Name {
// First, check if it's in the list of packages to remove.
var found bool
for _, epkName := range removeList {
if epkName.Name == epk.Name {
found = true
break
}
}
if !found {
fmt.Println(color.RedString("Package " + pkg.Name + " 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.
pkg.Priority++
}
}
}
}
}
if len(removeList) > 0 {
// First, re-order the packageRemoveList by priority, then alphabetically.
sort.Slice(removeList, func(i, j int) bool {
if removeList[i].Priority == removeList[j].Priority {
return removeList[i].Name < removeList[j].Name
}
return removeList[i].Priority > removeList[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("=")
}
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("=")
}
for _, pkg := range removeList {
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(pkg.DisplayData.DecompressedSize)
finalisedList[5] = "Remove"
for _, item := range finalisedList {
common.PrintWithEvenPadding(item, maxSize)
}
fmt.Println()
}
for range width {
fmt.Print("=")
}
fmt.Println("Transaction Summary")
fmt.Println("\nRemoving " + humanize.Comma(int64(len(removeList))) + " packages.")
space := new(big.Int)
for _, pkg := range removeList {
space = new(big.Int).Add(space, pkg.DisplayData.DecompressedSize)
}
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 removeList {
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)
}
} else {
fmt.Println("No packages to clean.")
os.Exit(0)
}
}
default: default:
fmt.Println(color.RedString("Unknown or unimplemented command: " + os.Args[1])) fmt.Println(color.RedString("Unknown or unimplemented command: " + os.Args[1]))
os.Exit(1) os.Exit(1)

View file

@ -61,7 +61,7 @@ type Plugin struct {
} }
var conn *sql.DB var conn *sql.DB
var dbVersion = semver.MustParse("1.0.0-beta.4") var dbVersion = semver.MustParse("1.0.0")
var DefaultLogger = lib.Logger{ var DefaultLogger = lib.Logger{
LogFunc: func(log lib.Log) string { LogFunc: func(log lib.Log) string {
@ -298,6 +298,7 @@ dependencyLoop:
if err != nil || vagueErr != nil { if err != nil || vagueErr != nil {
return nil, 0, err return nil, 0, err
} }
epkPreMap.DisplayData.IsDependency = true
// Set the EPKs display data. // Set the EPKs display data.
epkEntry.EPKPreMap = &epkPreMap epkEntry.EPKPreMap = &epkPreMap
if exists { if exists {
@ -501,7 +502,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 // 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. // 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, installedPaths 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, decompressedSize BLOB NOT NULL)")
if err != nil { if err != nil {
return err return err
} }
@ -654,7 +655,7 @@ func EstablishDBConnection(logger *lib.Logger) error {
return nil return nil
} }
func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, 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, decompressedSize *big.Int, repository ...string) error {
// If it already exists, delete it. This may happen in a force-install scenario. // If it already exists, delete it. This may happen in a force-install scenario.
_, err := conn.Exec("DELETE FROM packages WHERE name = ?", metadata.Name) _, err := conn.Exec("DELETE FROM packages WHERE name = ?", metadata.Name)
if err != nil { if err != nil {
@ -687,15 +688,15 @@ func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, removeSc
// Not that I'm complaining or anything. // Not that I'm complaining or anything.
// - Arzumify // - Arzumify
if len(repository) > 0 { if len(repository) > 0 {
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", _, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths, decompressedSize) VALUES (?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
metadata.Name, metadata.Description, metadata.LongDescription, metadata.Version.String(), metadata.Author, 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,
repository[0], installedPathsString) repository[0], installedPathsString, decompressedSize.Bytes())
} else { } else {
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, installedPaths) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", _, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, installedPaths, decompressedSize) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
metadata.Name, metadata.Description, metadata.LongDescription, metadata.Version.String(), metadata.Author, 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) installedPathsString, decompressedSize.Bytes())
} }
if err != nil { if err != nil {
return err return err
@ -739,11 +740,12 @@ func DefaultGetEPKFromDB(name string) (lib.Metadata, string, bool, bool, int64,
var repository string var repository string
var installedPaths string var installedPaths string
var size int64 var size int64
err := conn.QueryRow("SELECT description, longDescription, version, author, license, architecture, size, "+ var decompressedSize []byte
"dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths FROM packages WHERE name = ?", err := conn.QueryRow("SELECT description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths, decompressedSize FROM packages WHERE name = ?",
name).Scan(&metadata.Description, &metadata.LongDescription, &versionString, &metadata.Author, name).Scan(&metadata.Description, &metadata.LongDescription, &versionString, &metadata.Author,
&metadata.License, &metadata.Architecture, &size, &dependencies, &removeScript, &hasRemoveScript, &metadata.License, &metadata.Architecture, &size, &dependencies, &removeScript, &hasRemoveScript,
&dependency, &repository, &installedPaths) &dependency, &repository, &installedPaths, &decompressedSize)
metadata.DecompressedSize = big.NewInt(0).SetBytes(decompressedSize)
if err != nil { if err != nil {
return lib.Metadata{}, "", false, false, 0, "", nil, err return lib.Metadata{}, "", false, false, 0, "", nil, err
} }
@ -772,7 +774,7 @@ func DefaultRemoveEPKFromDB(name string) error {
} }
func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map[string]lib.Repository, map[string]int64, error) { 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") rows, err := conn.Query("SELECT name, description, version, author, architecture, size, dependencies, repository, isDependency, decompressedSize FROM packages")
if err != nil { if err != nil {
return nil, nil, nil, nil, err return nil, nil, nil, nil, err
} }
@ -788,11 +790,15 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
var dependencies string var dependencies string
var repository string var repository string
var version string var version string
err := rows.Scan(&metadata.Name, &metadata.Description, &version, var isDependency bool
&metadata.Author, &metadata.Architecture, &size, &dependencies, &repository) var decompressedSize []byte
err := rows.Scan(&metadata.Name, &metadata.Description, &version, &metadata.Author, &metadata.Architecture,
&size, &dependencies, &repository, &isDependency, &decompressedSize)
metadata.DecompressedSize = big.NewInt(0).SetBytes(decompressedSize)
if err != nil { if err != nil {
return nil, nil, nil, nil, err return nil, nil, nil, nil, err
} }
metadata.IsDependency = isDependency
semVer, err := semver.NewVersion(version) semVer, err := semver.NewVersion(version)
if err != nil { if err != nil {
return nil, nil, nil, nil, err return nil, nil, nil, nil, err
@ -811,8 +817,12 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
repo.Name = repository repo.Name = repository
err := conn.QueryRow("SELECT url, owner, description FROM repositories WHERE name = ?", repository).Scan(&repo.URL, &repo.Owner, &repo.Description) err := conn.QueryRow("SELECT url, owner, description FROM repositories WHERE name = ?", repository).Scan(&repo.URL, &repo.Owner, &repo.Description)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil, nil, nil, errors.New("repository " + repository + " not found")
} else {
return nil, nil, nil, nil, err return nil, nil, nil, nil, err
} }
}
repoNameToRepo[repository] = repo repoNameToRepo[repository] = repo
} }
// Add the repository to the repository map // Add the repository to the repository map

View file

@ -90,6 +90,7 @@ type DisplayData struct {
Size int64 Size int64
DecompressedSize *big.Int DecompressedSize *big.Int
Dependencies []string Dependencies []string
IsDependency bool
} }
// PotentiallyNullEPKPreMap is a EPKPreMap that can be nil // PotentiallyNullEPKPreMap is a EPKPreMap that can be nil
@ -848,7 +849,7 @@ func (writer *ProgressWriter) Write(p []byte) (n int, err error) {
} }
// InstallEPK installs an EPK file // InstallEPK installs an EPK file
func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, addEPKToDB func(*Metadata, []string, []byte, bool, bool, int64, ...string) error, logger *Logger) (string, error, error) { func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, addEPKToDB func(*Metadata, []string, []byte, bool, bool, int64, *big.Int, ...string) error, logger *Logger) (string, error, error) {
// Create the temporary directory // Create the temporary directory
tempDir, err := os.MkdirTemp("/tmp", "eon-install-") tempDir, err := os.MkdirTemp("/tmp", "eon-install-")
if err != nil { if err != nil {
@ -1191,9 +1192,9 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
var err error var err error
if !epkBytes.IsRemote { if !epkBytes.IsRemote {
err = addEPKToDB(metadata, installedFiles, []byte{}, false, false, metadata.Size) err = addEPKToDB(metadata, installedFiles, []byte{}, preMap.DisplayData.IsDependency, false, metadata.Size, metadata.DecompressedSize)
} else { } else {
err = addEPKToDB(metadata, installedFiles, []byte{}, false, false, metadata.Size, epkBytes.RepositoryName) err = addEPKToDB(metadata, installedFiles, []byte{}, preMap.DisplayData.IsDependency, false, metadata.Size, metadata.DecompressedSize, epkBytes.RepositoryName)
} }
if err != nil { if err != nil {
return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB
@ -1204,9 +1205,9 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
} else { } else {
var err error var err error
if !epkBytes.IsRemote { if !epkBytes.IsRemote {
err = addEPKToDB(metadata, installedFiles, file, false, true, metadata.Size) err = addEPKToDB(metadata, installedFiles, file, preMap.DisplayData.IsDependency, true, metadata.Size, metadata.DecompressedSize)
} else { } else {
err = addEPKToDB(metadata, installedFiles, file, false, true, metadata.Size, epkBytes.RepositoryName) err = addEPKToDB(metadata, installedFiles, file, preMap.DisplayData.IsDependency, true, metadata.Size, metadata.DecompressedSize, epkBytes.RepositoryName)
} }
if err != nil { if err != nil {
return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB