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.")
case "repo":
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("- list: lists repositories.")
case "help":
@ -197,6 +197,8 @@ func main() {
os.Exit(1)
}
preMap.DisplayData.IsDependency = false
var installPackage common.InstallPackage
installPackage.EPKPreMap = &preMap
installPackage.Url = ""
@ -321,6 +323,8 @@ func main() {
os.Exit(1)
}
preMap.DisplayData.IsDependency = false
// Map the data we have
epkEntry.Priority = 0
epkEntry.EPKPreMap = &preMap
@ -640,7 +644,7 @@ func main() {
switch os.Args[2] {
case "add":
if len(os.Args) < 4 {
fmt.Println("Usage: eon repo add <url>")
fmt.Println("Usage: eon repo add <packageUrl>")
os.Exit(1)
} else {
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:
fmt.Println(color.RedString("Unknown or unimplemented command: " + os.Args[1]))
os.Exit(1)

View file

@ -61,7 +61,7 @@ type Plugin struct {
}
var conn *sql.DB
var dbVersion = semver.MustParse("1.0.0-beta.4")
var dbVersion = semver.MustParse("1.0.0")
var DefaultLogger = lib.Logger{
LogFunc: func(log lib.Log) string {
@ -298,6 +298,7 @@ dependencyLoop:
if err != nil || vagueErr != nil {
return nil, 0, err
}
epkPreMap.DisplayData.IsDependency = true
// Set the EPKs display data.
epkEntry.EPKPreMap = &epkPreMap
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
// 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 {
return err
}
@ -654,7 +655,7 @@ func EstablishDBConnection(logger *lib.Logger) error {
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.
_, err := conn.Exec("DELETE FROM packages WHERE name = ?", metadata.Name)
if err != nil {
@ -687,15 +688,15 @@ func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, removeSc
// 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, 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.License, metadata.Architecture, size, dependencies, string(removeScript), hasRemoveScript, dependency,
repository[0], installedPathsString)
repository[0], installedPathsString, decompressedSize.Bytes())
} 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.License, metadata.Architecture, size, dependencies, string(removeScript), hasRemoveScript, dependency,
installedPathsString)
installedPathsString, decompressedSize.Bytes())
}
if err != nil {
return err
@ -739,11 +740,12 @@ func DefaultGetEPKFromDB(name string) (lib.Metadata, string, bool, bool, int64,
var repository string
var installedPaths string
var size int64
err := conn.QueryRow("SELECT description, longDescription, version, author, license, architecture, size, "+
"dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths FROM packages WHERE name = ?",
var decompressedSize []byte
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,
&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 {
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) {
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 {
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 repository string
var version string
err := rows.Scan(&metadata.Name, &metadata.Description, &version,
&metadata.Author, &metadata.Architecture, &size, &dependencies, &repository)
var isDependency bool
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 {
return nil, nil, nil, nil, err
}
metadata.IsDependency = isDependency
semVer, err := semver.NewVersion(version)
if err != nil {
return nil, nil, nil, nil, err
@ -811,7 +817,11 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
repo.Name = 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
if errors.Is(err, sql.ErrNoRows) {
return nil, nil, nil, nil, errors.New("repository " + repository + " not found")
} else {
return nil, nil, nil, nil, err
}
}
repoNameToRepo[repository] = repo
}

View file

@ -90,6 +90,7 @@ type DisplayData struct {
Size int64
DecompressedSize *big.Int
Dependencies []string
IsDependency bool
}
// 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
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
tempDir, err := os.MkdirTemp("/tmp", "eon-install-")
if err != nil {
@ -1191,9 +1192,9 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
if !errors.Is(err, os.ErrNotExist) {
var err error
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 {
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 {
return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB
@ -1204,9 +1205,9 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
} else {
var err error
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 {
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 {
return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB