Moved over to the eternity 2.0 format

This commit is contained in:
Arzumify 2024-10-10 10:24:56 +01:00
parent d2d6fcc8dd
commit 74861c6b0d
4 changed files with 251 additions and 136 deletions

BIN
cmd/cmd

Binary file not shown.

View file

@ -10,9 +10,9 @@ import (
"os"
"regexp"
"sort"
"strconv"
"strings"
"math/big"
"net/http"
"net/url"
@ -164,7 +164,7 @@ func main() {
var vagueErr error
var epkBytes bytes.Buffer
if !inMemoryMode {
preMap, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{FileStream: epkFile, IsFileStream: true}, fileInfos[pkg].Size())
preMap, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{FileStream: epkFile, IsFileStream: true}, uint64(fileInfos[pkg].Size()))
} else {
_, err = io.Copy(bufio.NewWriter(&epkBytes), epkFile)
if err != nil {
@ -172,11 +172,11 @@ func main() {
", have you tried disabling in-memory mode?"))
os.Exit(1)
}
err := epkFile.Close()
err = epkFile.Close()
if err != nil {
fmt.Println(color.HiYellowString("Failed to close package file: " + err.Error() + ", memory leak possible."))
}
preMap, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{Bytes: epkBytes.Bytes()}, fileInfos[pkg].Size())
preMap, err, vagueErr = lib.PreMapEPK(lib.StreamOrBytes{Bytes: epkBytes.Bytes()}, uint64(fileInfos[pkg].Size()))
}
if err != nil || vagueErr != nil {
common.PreMapEPKHandleError(err, vagueErr, logger)
@ -229,13 +229,13 @@ func main() {
if exists {
if version.Compare(&preMap.DisplayData.Version) != -1 {
if !forceMode {
skipEpk := []string{preMap.DisplayData.Name, preMap.DisplayData.Architecture, preMap.DisplayData.Version.String(), "Local file", humanize.BigIBytes(preMap.DisplayData.DecompressedSize), "Skip"}
skipEpk := []string{preMap.DisplayData.Name, preMap.DisplayData.Architecture, preMap.DisplayData.Version.String(), "Local file", humanize.Bytes(preMap.DisplayData.DecompressedSize), "Skip"}
skipEpkList = append(skipEpkList, skipEpk)
} else {
installPackage.IsForced = true
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, common.DefaultListEPKsInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -247,7 +247,7 @@ func main() {
} else {
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, common.DefaultListEPKsInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -260,7 +260,7 @@ func main() {
preMap.IsUpgrade = false
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
epkList, addedDeps, err = common.HandleDependencies(dependencies, installPackage, 0, []lib.RemoteEPK{}, common.DefaultListRemotePackagesInDB, common.DefaultListEPKsInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -351,11 +351,14 @@ func main() {
}
// Calculate the total size of the package
contentLength := new(big.Int)
contentLength.SetString(epkBytes.Header.Get("Content-Length"), 10)
contentLength, err := strconv.ParseUint(epkBytes.Header.Get("Content-Length"), 10, 64)
if err != nil {
fmt.Println(color.RedString("Failed to get content length: " + err.Error()))
os.Exit(1)
}
// Print that we are downloading the package
fmt.Println("\nDownloading package: " + preMap.DisplayData.Name + " (" + humanize.BigIBytes(contentLength) + ")")
fmt.Println("\nDownloading package: " + preMap.DisplayData.Name + " (" + humanize.Bytes(contentLength) + ")")
// Hide the cursor for reasons explained below.
fmt.Print("\033[?25l")
@ -375,8 +378,8 @@ func main() {
// Set the progress to 100%
logger.LogFunc(lib.Log{
Level: "PROGRESS",
Progress: big.NewInt(1),
Total: big.NewInt(1),
Progress: 1,
Total: 1,
})
// Show the cursor again because we're done with the progress bar.
@ -402,14 +405,14 @@ func main() {
if version.Compare(&preMap.DisplayData.Version) != -1 {
// If the version is the same or newer, skip the package.
if !forceMode {
skipEpkList = append(skipEpkList, []string{preMap.DisplayData.Name, preMap.DisplayData.Architecture, preMap.DisplayData.Version.String(), remoteEPK.Repository.Name, humanize.BigIBytes(preMap.DisplayData.DecompressedSize), "Skip"})
skipEpkList = append(skipEpkList, []string{preMap.DisplayData.Name, preMap.DisplayData.Architecture, preMap.DisplayData.Version.String(), remoteEPK.Repository.Name, humanize.Bytes(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.
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, common.DefaultListEPKsInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -423,7 +426,7 @@ func main() {
// If the version is older, install it.
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, common.DefaultListEPKsInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -436,7 +439,7 @@ func main() {
// If the package is not installed, install it.
var emptyList []string
var addedDeps int
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, epkList, &emptyList, logger)
epkList, addedDeps, err = common.HandleDependencies(dependencies, epkEntry, 0, remoteEpkList, common.DefaultListRemotePackagesInDB, common.DefaultListEPKsInDB, epkList, &emptyList, logger)
if err != nil {
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
os.Exit(1)
@ -497,7 +500,7 @@ func main() {
} else {
finalisedList[3] = pkg.Repository.Name
}
finalisedList[4] = humanize.BigIBytes(pkg.EPKPreMap.DisplayData.DecompressedSize)
finalisedList[4] = humanize.Bytes(pkg.EPKPreMap.DisplayData.DecompressedSize)
if pkg.IsForced {
finalisedList[5] = "Forced installation"
} else if pkg.EPKPreMap.IsUpgrade {
@ -516,8 +519,8 @@ func main() {
}
fmt.Println("Transaction Summary")
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")
fmt.Println("Total download size: " + humanize.Bytes(common.GetTotalSize(epkList)))
fmt.Println("Total installed size: " + humanize.Bytes(common.GetTotalInstalledSize(epkList)) + "\n")
var response string
if !yesMode {
response = logger.LogFunc(lib.Log{
@ -557,8 +560,12 @@ func main() {
}
// 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) + ")")
contentLength, err := strconv.ParseUint(epkBytes.Header.Get("Content-Length"), 10, 64)
if err != nil {
fmt.Println(color.RedString("Failed to get content length: " + err.Error()))
os.Exit(1)
}
fmt.Println("\nDownloading package: " + installPackage.EPKPreMap.DisplayData.Name + " (" + humanize.Bytes(contentLength) + ")")
var buffer bytes.Buffer
_, err = io.Copy(&lib.ProgressWriter{
Logger: logger,
@ -573,8 +580,8 @@ func main() {
// Set the progress to 100%
logger.LogFunc(lib.Log{
Level: "PROGRESS",
Progress: big.NewInt(1),
Total: big.NewInt(1),
Progress: 1,
Total: 1,
})
// Close the response body
@ -794,7 +801,7 @@ func main() {
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[4] = humanize.Bytes(decompressedSizeMap[pkg.Name])
finalisedList[5] = "Remove"
for _, item := range finalisedList {
common.PrintWithEvenPadding(item, maxSize)
@ -805,11 +812,11 @@ func main() {
}
fmt.Println("Transaction Summary")
fmt.Println("\nRemoving " + humanize.Comma(int64(len(packageRemoveList))) + " packages.")
space := new(big.Int)
var space uint64
for _, pkg := range packageRemoveList {
space = new(big.Int).Add(space, decompressedSizeMap[pkg.Name])
space += decompressedSizeMap[pkg.Name]
}
fmt.Println("Total reclaimed space: " + humanize.BigIBytes(space) + "\n")
fmt.Println("Total reclaimed space: " + humanize.Bytes(space) + "\n")
response := logger.LogFunc(lib.Log{
Level: "INFO",
Content: "Proceed with removal (y/n)?",
@ -1044,10 +1051,10 @@ func main() {
common.PrintWithEvenPadding(metadata.Architecture, width/2)
common.PrintWithEvenPadding("Installed Size", width/2)
common.PrintWithEvenPadding(humanize.BigIBytes(metadata.DecompressedSize), width/2)
common.PrintWithEvenPadding(humanize.Bytes(metadata.DecompressedSize), width/2)
common.PrintWithEvenPadding("Download Size", width/2)
common.PrintWithEvenPadding(humanize.Bytes(uint64(metadata.Size)), width/2)
common.PrintWithEvenPadding(humanize.Bytes(metadata.Size), width/2)
common.PrintWithEvenPadding("Repository", width/2)
common.PrintWithEvenPadding(remoteEpk.Repository.Name, width/2)
@ -1162,7 +1169,7 @@ func main() {
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[4] = humanize.Bytes(pkg.DisplayData.DecompressedSize)
finalisedList[5] = "Remove"
for _, item := range finalisedList {
common.PrintWithEvenPadding(item, maxSize)
@ -1176,11 +1183,11 @@ func main() {
fmt.Println("Transaction Summary")
fmt.Println("\nRemoving " + humanize.Comma(int64(len(removeList))) + " packages.")
space := new(big.Int)
var space uint64
for _, pkg := range removeList {
space = new(big.Int).Add(space, pkg.DisplayData.DecompressedSize)
space += pkg.DisplayData.DecompressedSize
}
fmt.Println("Total reclaimed space: " + humanize.BigIBytes(space) + "\n")
fmt.Println("Total reclaimed space: " + humanize.Bytes(space) + "\n")
response := logger.LogFunc(lib.Log{
Level: "INFO",

View file

@ -19,7 +19,6 @@ import (
"crypto/ed25519"
"database/sql"
"encoding/binary"
"math/big"
"net/http"
"net/url"
@ -62,8 +61,8 @@ type Plugin struct {
var conn *sql.DB
// Database is no longer compatible with version 1.0.0
var dbVersion = semver.MustParse("2.0.0")
// Database is no longer compatible with versions below 3.0.0.
var dbVersion = semver.MustParse("3.0.0")
var DefaultLogger = lib.Logger{
LogFunc: func(log lib.Log) string {
@ -82,14 +81,11 @@ var DefaultLogger = lib.Logger{
os.Exit(1)
case "PROGRESS":
// Maths time! We need to calculate the percentage of the progress bar.
// Convert the total and progress to big.Floats so we can do division.
floatTotal := new(big.Float)
floatProgress := new(big.Float)
floatTotal.SetInt(log.Total)
floatProgress.SetInt(log.Progress)
// Calculate the fraction we need to multiply by 100 to get the percentage.
percentageBig := new(big.Float).Quo(floatProgress, floatTotal)
percentage, _ := percentageBig.Float64()
// Convert the total and progress to floats so we can do division.
var floatTotal = float64(log.Total)
var floatProgress = float64(log.Progress)
// Calculate the percentage.
var percentage = floatProgress / floatTotal
// 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 {
@ -195,7 +191,7 @@ 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, previousPackages *[]string, logger *lib.Logger) ([]InstallPackage, int, error) {
func HandleDependencies(previousDeps int, targetEPK InstallPackage, parentPriority int, epkList []lib.RemoteEPK, listRemotePackagesInDB func() ([]lib.RemoteEPK, error), listEPKsInDB func() (map[string]lib.DisplayData, map[string]uint64, map[string]lib.Repository, map[string]uint64, 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.DisplayData.Dependencies {
@ -223,7 +219,7 @@ dependencyLoop:
// Add the dependency to the list of previous packages.
*previousPackages = append(*previousPackages, targetEPK.EPKPreMap.DisplayData.Name)
// Recursively handle dependencies.
installedPackage, addedDeps, err := HandleDependencies(previousDeps, epk, parentPriority+1, epkList, ListRemotePackagesInDB, InstallPackageList, previousPackages, logger)
installedPackage, addedDeps, err := HandleDependencies(previousDeps, epk, parentPriority+1, epkList, listRemotePackagesInDB, listEPKsInDB, InstallPackageList, previousPackages, logger)
InstallPackageList = installedPackage
if err != nil {
return nil, 0, err
@ -242,7 +238,7 @@ dependencyLoop:
// Check if we already have a list of remote EPKs to use, if so use it.
if len(epkList) == 0 || epkList == nil {
var err error
epkList, err = ListRemotePackagesInDB()
epkList, err = listRemotePackagesInDB()
if err != nil {
return nil, 0, err
}
@ -267,7 +263,7 @@ dependencyLoop:
} else {
// Check if the installed version is outdated.
if version.LessThan(&epk.Version) {
// Yes it is: Install the new version as an upgrade.
// Yes it is: add it to the list of EPKs to install.
remoteEPK = epk
break
} else {
@ -277,10 +273,27 @@ dependencyLoop:
}
}
}
// If the dependency doesn't exist, crash.
if !dependencyExists {
return nil, 0, errors.New("dependency " + dependency + " does not exist")
// Iterate through the list of installed EPKs to find the dependency.
installedEPKs, _, _, _, err := listEPKsInDB()
if err != nil {
return nil, 0, err
}
for installedEPK := range installedEPKs {
if installedEPK == dependency {
// The dependency is installed. Exit the loop.
continue dependencyLoop
}
}
// If the dependency still doesn't exist, crash.
if !dependencyExists {
return nil, 0, errors.New("dependency " + dependency + " does not exist")
}
}
// Increase the dependency's priority.
epkEntry.Priority = parentPriority + 1
// Add the dependency to the list of EPKs to install.
@ -327,7 +340,7 @@ dependencyLoop:
// Add the dependency to the list of previous packages.
*previousPackages = append(*previousPackages, epkEntry.EPKPreMap.DisplayData.Name)
// Recursively handle dependencies.
installPackages, addedDeps, err := HandleDependencies(previousDeps, epkEntry, epkEntry.Priority+1, epkList, ListRemotePackagesInDB, InstallPackageList, previousPackages, logger)
installPackages, addedDeps, err := HandleDependencies(previousDeps, epkEntry, epkEntry.Priority+1, epkList, listRemotePackagesInDB, listEPKsInDB, InstallPackageList, previousPackages, logger)
InstallPackageList = installPackages
if err != nil {
return nil, 0, err
@ -346,19 +359,19 @@ dependencyLoop:
return InstallPackageList, previousDeps, nil
}
func GetTotalSize(InstallPackageList []InstallPackage) *big.Int {
totalSize := new(big.Int)
func GetTotalSize(InstallPackageList []InstallPackage) uint64 {
var totalSize uint64
for _, epk := range InstallPackageList {
totalSize.Add(totalSize, big.NewInt(epk.EPKPreMap.DisplayData.Size))
totalSize += epk.EPKPreMap.DisplayData.Size
}
return totalSize
}
func GetTotalInstalledSize(InstallPackageList []InstallPackage) *big.Int {
totalSize := new(big.Int)
func GetTotalInstalledSize(InstallPackageList []InstallPackage) uint64 {
var totalSize uint64
for _, epk := range InstallPackageList {
if !epk.IsRemote {
totalSize.Add(totalSize, epk.EPKPreMap.DisplayData.DecompressedSize)
totalSize += epk.EPKPreMap.DisplayData.DecompressedSize
}
}
return totalSize
@ -504,7 +517,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, decompressedSize BLOB NOT NULL)")
_, 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 INTEGER NOT NULL)")
if err != nil {
return err
}
@ -521,19 +534,15 @@ func InitDB(conn *sql.DB) error {
}
_, err = conn.Exec("INSERT INTO repositories (url, name, owner, description, ignore) VALUES ('None', 'Local file', 'eon', 'This is a placeholder repository for local files to be registered to. Do not attempt to use this repository.', true)")
if err != nil {
return err
}
// Way to big. Blame IntelliJ.
_, err = conn.Exec("CREATE TABLE remotePackages (name TEXT NOT NULL UNIQUE, author TEXT NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL, architecture TEXT NOT NULL, size BLOB NOT NULL, dependencies TEXT NOT NULL, path TEXT NOT NULL, arch TEXT NOT NULL, hash TEXT NOT NULL, repository TEXT NOT NULL)")
if err != nil {
return err
}
// Having exists here makes sure that there is only one global row in the table. This is a bit of a hack,
// but it's the only way to make sure that the version and endian-ness are always part of the database.
// Note that this is the only hack in this program (so far)! I feel somewhat proud, especially since it's less of
// a hack and more not utilizing the full power of SQL.
// - Arzumify
_, err = conn.Exec("CREATE TABLE global (version TEXT NOT NULL, uniquenessCheck BOOLEAN NOT NULL UNIQUE CHECK (uniquenessCheck = true) DEFAULT true)")
if err != nil {
return err
@ -659,7 +668,7 @@ func EstablishDBConnection(logger *lib.Logger) error {
return nil
}
func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, removeScript []byte, dependency bool, hasRemoveScript bool, size int64, decompressedSize *big.Int, repository string) error {
func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, removeScript []byte, dependency bool, hasRemoveScript bool, size uint64, decompressedSize uint64, 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 {
@ -694,7 +703,7 @@ func DefaultAddEPKToDB(metadata *lib.Metadata, installedPaths []string, removeSc
_, 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, installedPathsString, decompressedSize.Bytes())
repository, installedPathsString, decompressedSize)
if err != nil {
return err
}
@ -737,12 +746,10 @@ func DefaultGetEPKFromDB(name string) (lib.Metadata, string, bool, bool, int64,
var repository string
var installedPaths string
var size int64
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, &decompressedSize)
metadata.DecompressedSize = big.NewInt(0).SetBytes(decompressedSize)
&dependency, &repository, &installedPaths, &metadata.DecompressedSize)
if err != nil {
return lib.Metadata{}, "", false, false, 0, "", nil, err
}
@ -770,7 +777,7 @@ func DefaultRemoveEPKFromDB(name string) error {
return nil
}
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]uint64, map[string]lib.Repository, map[string]uint64, error) {
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
@ -779,19 +786,17 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
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)
sizes := make(map[string]uint64)
compressedSizes := make(map[string]uint64)
for rows.Next() {
var metadata lib.DisplayData
var size int64
var size uint64
var dependencies string
var repository string
var version string
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)
&size, &dependencies, &repository, &isDependency, &metadata.DecompressedSize)
if err != nil {
return nil, nil, nil, nil, err
}
@ -804,7 +809,7 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
metadata.Version = *semVer
metadata.Dependencies = strings.Split(strings.TrimSuffix(strings.TrimPrefix(dependencies, "["), "]"), ", ")
metadataMap[metadata.Name] = metadata
sizes[metadata.Name] = big.NewInt(size)
sizes[metadata.Name] = size
compressedSizes[metadata.Name] = size
// Check if the repository is in the repoNameToRepo map
var repo lib.Repository
@ -990,7 +995,7 @@ func DefaultListRemotePackagesInDB() ([]lib.RemoteEPK, error) {
for rows.Next() {
var name, author, description, version, architecture, dependencies, path, arch, repository string
var hashBytes []byte
var size int64
var size uint64
err := rows.Scan(&name, &author, &description, &version, &architecture, &size, &dependencies, &path, &arch,
&hashBytes, &repository)
if err != nil {

View file

@ -15,7 +15,6 @@ import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"math/big"
"net/http"
"net/url"
"os/exec"
@ -35,7 +34,7 @@ type RemoteEPK struct {
Description string
Version semver.Version
Architecture string
CompressedSize int64
CompressedSize uint64
Dependencies []string
Path string
Arch string
@ -67,8 +66,8 @@ type Metadata struct {
Architecture string
Dependencies []string
SpecialFiles SpecialFiles
Size int64
DecompressedSize *big.Int
Size uint64
DecompressedSize uint64
}
// EPKPreMap is a struct that contains the metadata of the EPK
@ -77,7 +76,7 @@ type EPKPreMap struct {
MetadataMap map[string]interface{}
IsLittleEndian bool
IsUpgrade bool
TarOffset int64
TarOffset uint64
}
// DisplayData is a struct that contains the display data of the EPK
@ -87,8 +86,8 @@ type DisplayData struct {
Architecture string
Description string
Version semver.Version
Size int64
DecompressedSize *big.Int
Size uint64
DecompressedSize uint64
Dependencies []string
IsDependency bool
}
@ -105,8 +104,8 @@ type Log struct {
Content string
Prompt bool
PlaySound bool
Progress *big.Int
Total *big.Int
Progress uint64
Total uint64
Overwrite bool
}
@ -203,10 +202,12 @@ func MkdirAllWithPaths(path string, perm os.FileMode) ([]string, error) {
return createdDirs, nil
}
func preMapEpkFromBytes(metaDataBytes []byte, littleEndian bool, size int64, offset int64) (EPKPreMap, error) {
func preMapEpkFromBytes(metaDataBytes []byte, littleEndian bool, size uint64, offset uint64) (EPKPreMap, error) {
// Unmarshal the JSON
var displayDataMap map[string]interface{}
err := json.Unmarshal(metaDataBytes, &displayDataMap)
decoder := json.NewDecoder(bytes.NewReader(metaDataBytes))
decoder.UseNumber()
err := decoder.Decode(&displayDataMap)
if err != nil {
return EPKPreMap{}, errors.New("metadata is not valid JSON")
}
@ -223,12 +224,14 @@ func preMapEpkFromBytes(metaDataBytes []byte, littleEndian bool, size int64, off
// Map the display data
var ok bool
// Set the size
sizeBigInt, ok := displayDataMap["size"].(string)
sizeJSON, ok := displayDataMap["size"].(json.Number)
if !ok {
return EPKPreMap{}, errors.New("size is not a string")
return EPKPreMap{}, errors.New("size is not a number")
}
parsedDisplayData.DisplayData.DecompressedSize, err = strconv.ParseUint(sizeJSON.String(), 10, 64)
if err != nil {
return EPKPreMap{}, err
}
parsedDisplayData.DisplayData.DecompressedSize = new(big.Int)
parsedDisplayData.DisplayData.DecompressedSize.SetString(sizeBigInt, 10)
// Set the name, author, version, arch, and dependencies
parsedDisplayData.DisplayData.Name, ok = displayDataMap["name"].(string)
if !ok {
@ -264,7 +267,7 @@ func preMapEpkFromBytes(metaDataBytes []byte, littleEndian bool, size int64, off
}
// ConstMapEPKMetadataOffset is the offset of the metadata in the EPK: 3 magic bytes, 1 endian byte, 8 offset bytes, 64 signature bytes, and 32 public key bytes
var ConstMapEPKMetadataOffset int64 = 108
var ConstMapEPKMetadataOffset uint64 = 108
var ErrPreMapEPKCouldNotRead = errors.New("could not read EPK")
var ErrPreMapEPKHasNetworkStream = errors.New("network streams are not supported")
@ -273,7 +276,7 @@ var ErrPreMapEPKHasInvalidEndian = errors.New("has invalid endian")
var ErrPreMapEPKCouldNotMapJSON = errors.New("could not map metadata")
// PreMapEPK maps enough data to create the display summary of an EPK
func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error) {
func PreMapEPK(epkBytes StreamOrBytes, epkSize uint64) (EPKPreMap, error, error) {
// Say that we don't support network streams
if epkBytes.IsURL {
return EPKPreMap{}, nil, ErrPreMapEPKHasNetworkStream
@ -321,7 +324,7 @@ func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error)
}
// Now we can get the offsets of the tar archive
var tarArchiveOffset int64
var tarArchiveOffset uint64
if epkBytes.IsFileStream {
var tarArchiveOffsetBytes = make([]byte, 8)
_, err := epkBytes.FileStream.ReadAt(tarArchiveOffsetBytes, 4)
@ -329,15 +332,15 @@ func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error)
return EPKPreMap{}, err, ErrPreMapEPKCouldNotRead
}
if littleEndian {
tarArchiveOffset = int64(binary.LittleEndian.Uint64(tarArchiveOffsetBytes))
tarArchiveOffset = binary.LittleEndian.Uint64(tarArchiveOffsetBytes)
} else {
tarArchiveOffset = int64(binary.BigEndian.Uint64(tarArchiveOffsetBytes))
tarArchiveOffset = binary.BigEndian.Uint64(tarArchiveOffsetBytes)
}
} else {
if littleEndian {
tarArchiveOffset = int64(binary.LittleEndian.Uint64(epkBytes.Bytes[4:12]))
tarArchiveOffset = binary.LittleEndian.Uint64(epkBytes.Bytes[4:12])
} else {
tarArchiveOffset = int64(binary.BigEndian.Uint64(epkBytes.Bytes[4:12]))
tarArchiveOffset = binary.BigEndian.Uint64(epkBytes.Bytes[4:12])
}
}
@ -346,11 +349,14 @@ func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error)
var preMapEpk EPKPreMap
if epkBytes.IsFileStream {
var metadataBuffer = make([]byte, tarArchiveOffset-ConstMapEPKMetadataOffset)
_, err := epkBytes.FileStream.ReadAt(metadataBuffer, ConstMapEPKMetadataOffset)
_, err := epkBytes.FileStream.ReadAt(metadataBuffer, int64(ConstMapEPKMetadataOffset))
if err != nil {
return EPKPreMap{}, err, ErrPreMapEPKCouldNotRead
}
preMapEpk, err = preMapEpkFromBytes(metadataBuffer, littleEndian, epkSize, tarArchiveOffset)
if err != nil {
return EPKPreMap{}, err, ErrPreMapEPKCouldNotMapJSON
}
} else {
var err error
preMapEpk, err = preMapEpkFromBytes(epkBytes.Bytes[ConstMapEPKMetadataOffset:tarArchiveOffset], littleEndian, epkSize, tarArchiveOffset)
@ -445,11 +451,11 @@ func PreMapRemoteEPK(remoteEPK RemoteEPK, logger *Logger) (EPKPreMap, error, err
}
// Now we can get the offsets of the tar archive
var tarArchiveOffset int64
var tarArchiveOffset uint64
if littleEndian {
tarArchiveOffset = int64(binary.LittleEndian.Uint64(epkHeaderBytes[4:12]))
tarArchiveOffset = binary.LittleEndian.Uint64(epkHeaderBytes[4:12])
} else {
tarArchiveOffset = int64(binary.BigEndian.Uint64(epkHeaderBytes[4:12]))
tarArchiveOffset = binary.BigEndian.Uint64(epkHeaderBytes[4:12])
}
// No signature verification for you
@ -458,7 +464,7 @@ func PreMapRemoteEPK(remoteEPK RemoteEPK, logger *Logger) (EPKPreMap, error, err
displayDataBytes := make([]byte, tarArchiveOffset-ConstMapEPKMetadataOffset)
if rangeSupported {
// Send another request to fetch the display data
req.Header.Set("Range", "bytes=108-"+strconv.FormatInt(tarArchiveOffset-1, 10))
req.Header.Set("Range", "bytes=108-"+strconv.FormatUint(tarArchiveOffset-1, 10))
resp, err = http.DefaultClient.Do(req)
if err != nil {
return EPKPreMap{}, err, ErrPreMapRemoteEPKCouldNotSendRequest
@ -690,7 +696,7 @@ func FullyMapMetadata(epkBytes StreamOrBytes, preMap *EPKPreMap, checkFingerprin
if epkBytes.IsFileStream {
// Now we can verify the signature. First, we need to take the checksum of the metadata
// Seeking is better than using ReadAt because it allows us to not have to load the entire file into memory
_, err = epkBytes.FileStream.Seek(ConstMapEPKMetadataOffset, io.SeekStart)
_, err = epkBytes.FileStream.Seek(int64(ConstMapEPKMetadataOffset), io.SeekStart)
if err != nil {
return &Metadata{}, err, ErrFullyMapMetadataCouldNotJump
}
@ -789,12 +795,14 @@ func FullyMapMetadata(epkBytes StreamOrBytes, preMap *EPKPreMap, checkFingerprin
if !ok {
return &Metadata{}, errors.New("license is not a string"), ErrFullyMapMetadataCouldNotMapJSON
}
decompressedSizeString, ok := preMap.MetadataMap["size"].(string)
decompressedSizeJSON, ok := preMap.MetadataMap["size"].(json.Number)
if !ok {
return &Metadata{}, errors.New("size is not a string"), ErrFullyMapMetadataCouldNotMapJSON
return &Metadata{}, errors.New("size is not a number"), ErrFullyMapMetadataCouldNotMapJSON
}
parsedMetadata.DecompressedSize, err = strconv.ParseUint(decompressedSizeJSON.String(), 10, 64)
if err != nil {
return &Metadata{}, err, ErrFullyMapMetadataCouldNotMapJSON
}
parsedMetadata.DecompressedSize = new(big.Int)
parsedMetadata.DecompressedSize.SetString(decompressedSizeString, 10)
return &parsedMetadata, nil, nil
}
@ -815,15 +823,15 @@ var ErrInstallEPKCouldNotRemoveTempDir = errors.New("could not remove temporary
// ProgressWriter implements a writer that intercepts writes in order to log progress
type ProgressWriter struct {
Logger *Logger
Total *big.Int
Total uint64
Writer io.Writer
}
// Write writes to the ProgressWriter
func (writer *ProgressWriter) Write(p []byte) (n int, err error) {
byteCount := new(big.Int)
var byteCount uint64
for range p {
byteCount.Add(byteCount, big.NewInt(1))
byteCount++
}
if writer.Logger.ProgressSupported {
writer.Logger.LogFunc(Log{
@ -835,7 +843,7 @@ func (writer *ProgressWriter) Write(p []byte) (n int, err error) {
} else {
writer.Logger.LogFunc(Log{
Level: "INFO",
Content: "Written " + humanize.BigIBytes(byteCount) + " out of " + humanize.BigIBytes(writer.Total),
Content: "Written " + humanize.Bytes(byteCount) + " out of " + humanize.Bytes(writer.Total),
Prompt: false,
})
}
@ -849,7 +857,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, *big.Int, string) error, logger *Logger) (string, error, error) {
func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, addEPKToDB func(*Metadata, []string, []byte, bool, bool, uint64, uint64, string) error, logger *Logger) (string, error, error) {
// Create the temporary directory
tempDir, err := os.MkdirTemp("/tmp", "eon-install-")
if err != nil {
@ -860,7 +868,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
var connection io.ReadCloser
if epkBytes.IsFileStream {
// Seek to the correct position in the EPK
_, err = epkBytes.FileStream.Seek(preMap.TarOffset, io.SeekStart)
_, err = epkBytes.FileStream.Seek(int64(preMap.TarOffset), io.SeekStart)
if err != nil {
return "", err, nil
}
@ -877,7 +885,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
return tempDir, err, ErrInstallEPKCouldNotCreateZStandardReader
}
// Set the range header
req.Header.Set("Range", "bytes="+strconv.FormatInt(preMap.TarOffset, 10)+"-")
req.Header.Set("Range", "bytes="+strconv.FormatUint(preMap.TarOffset, 10)+"-")
// Send the request
resp, err := http.DefaultClient.Do(req)
if err != nil {
@ -892,9 +900,9 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
// God this is painful. Let's give the user a progress bar to make it less painful
_, err := io.CopyN(&ProgressWriter{
Logger: logger,
Total: big.NewInt(preMap.TarOffset),
Total: preMap.TarOffset,
Writer: io.Discard,
}, connection, preMap.TarOffset)
}, connection, int64(preMap.TarOffset))
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
}
@ -919,7 +927,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
tarReader := tar.NewReader(zStandardReader)
// Create a goroutine to see how much of the decompressed size we have decompressed
written := new(big.Int)
var written uint64
stop := make(chan bool)
go func() {
for {
@ -937,7 +945,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
} else {
logger.LogFunc(Log{
Level: "INFO",
Content: "Decompressed " + humanize.Bytes(uint64(written.Int64())) + " of " + humanize.Bytes(uint64(metadata.DecompressedSize.Int64())),
Content: "Decompressed " + humanize.Bytes(written) + " of " + humanize.Bytes(metadata.DecompressedSize),
Prompt: false,
})
time.Sleep(1 * time.Second)
@ -1067,19 +1075,12 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
}
written.Add(written, big.NewInt(writtenFile))
written += uint64(writtenFile)
err = file.Close()
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCloseTarReader
} else {
// Check if the files are in noDelete
for _, file := range metadata.SpecialFiles.NoDelete {
if strings.TrimSuffix(target, "/") == strings.TrimSuffix(file, "/") {
// This file is a special file and should not be deleted
continue
}
}
if !isHook {
// Add the file to the installed files
installedFiles = append(installedFiles, target)
@ -1099,6 +1100,108 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
}
}
}
// It's not special, so we can replace it
file, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode))
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCreateFile
}
writtenFile, err := io.Copy(file, tarReader)
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
}
written += uint64(writtenFile)
err = file.Close()
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCloseTarReader
} else {
if !isHook {
// Add the file to the installed files
installedFiles = append(installedFiles, target)
}
}
}
case tar.TypeSymlink:
// Check if the symlink has anywhere to go
_, err := os.Stat(filepath.Dir(target))
if err != nil {
// No, it doesn't. Create the directory
if errors.Is(err, os.ErrNotExist) {
// We assume 0755 for directories
paths, err := MkdirAllWithPaths(filepath.Dir(target), 0755)
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCreateDir
} else {
// Check if the files are in noDelete
for _, file := range metadata.SpecialFiles.NoDelete {
if strings.TrimSuffix(target, "/") == strings.TrimSuffix(file, "/") {
// This file is a special file and should not be deleted
continue
}
}
if !isHook {
// Add the directory to the installed files
installedFiles = append(installedFiles, filepath.Dir(target))
// Add the paths to the installed files
if paths != nil {
installedFiles = append(installedFiles, paths...)
}
}
}
} else {
return tempDir, err, ErrInstallEPKCouldNotStatDir
}
}
// Check if the symlink already exists
_, err = os.Lstat(target)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
// Great, the symlink does not exist. Let's create it.
err = os.Symlink(header.Linkname, target)
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCreateFile
} else {
if !isHook {
// Add the symlink to the installed files
installedFiles = append(installedFiles, target)
}
}
} else {
return tempDir, err, ErrInstallEPKCouldNotStatFile
}
} else {
// See if it's an upgrade or not
if preMap.IsUpgrade {
// Check if it's a special file
for _, file := range metadata.SpecialFiles.NoReplace {
if strings.TrimSuffix(target, "/") == strings.TrimSuffix(file, "/") {
// This file is a special file and should not be replaced
continue
}
}
}
// It's not special, so we can replace it
err = os.Remove(target)
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCreateFile
}
err = os.Symlink(header.Linkname, target)
if err != nil {
return tempDir, err, ErrInstallEPKCouldNotCreateFile
} else {
if !isHook {
// Add the symlink to the installed files
installedFiles = append(installedFiles, target)
}
}
}
}
}
@ -1223,8 +1326,8 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
stop <- true
logger.LogFunc(Log{
Level: "PROGRESS",
Progress: big.NewInt(1),
Total: big.NewInt(1),
Progress: 1,
Total: 1,
Overwrite: true,
})
@ -1414,12 +1517,12 @@ func AddRepository(url string, addRepositoryToDB func(Repository, bool) error, g
return "", errors.New("package version is not a valid semver version"), ErrAddRepositoryHasInvalidMetadata
}
sizeString, ok := epk["size"].(string)
sizeString, ok := epk["size"].(json.Number)
if !ok {
return "", errors.New("package size is not a string"), ErrAddRepositoryHasInvalidMetadata
return "", errors.New("package size is not a number"), ErrAddRepositoryHasInvalidMetadata
}
size, err := strconv.ParseInt(sizeString, 10, 64)
size, err := strconv.ParseUint(sizeString.String(), 10, 64)
if err != nil {
return "", errors.New("package size is not a number"), ErrAddRepositoryHasInvalidMetadata
}