Compare commits
10 commits
39f15e7e1e
...
0fa66c1125
Author | SHA1 | Date | |
---|---|---|---|
0fa66c1125 | |||
|
74861c6b0d | ||
|
d2d6fcc8dd | ||
|
791b3a5fb9 | ||
|
511379317a | ||
|
b6ca866479 | ||
|
f903fe44dd | ||
|
6fcd316f39 | ||
|
b329a7ba52 | ||
|
64d4174edd |
8 changed files with 692 additions and 168 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
.idea
|
.idea
|
||||||
|
/bin
|
23
Makefile
Normal file
23
Makefile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
DESTDIR ?= /usr
|
||||||
|
BUILDDIR ?= dist
|
||||||
|
CGO_ENABLED ?= 0
|
||||||
|
|
||||||
|
all: cmd
|
||||||
|
|
||||||
|
cmd ./cmd/eon/main.go:
|
||||||
|
mkdir -p $(BUILDDIR)/bin
|
||||||
|
go build -o $(BUILDDIR)/bin/eon ./cmd/eon -ldflags "-s -w"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
install:
|
||||||
|
install -d $(DESTDIR)/bin
|
||||||
|
install -m 755 $(BUILDDIR)/bin/eon $(DESTDIR)/bin/eon
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(DESTDIR)/bin/eon
|
||||||
|
|
||||||
|
test:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILDDIR)
|
13
build.sh
Executable file
13
build.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Create the bin directory
|
||||||
|
mkdir -p bin
|
||||||
|
|
||||||
|
# Build the CLI
|
||||||
|
echo "Building the CLI..."
|
||||||
|
CGO_ENABLED=0 go build -ldflags "-s -w" -o ./bin/eon ./cmd/main.go
|
||||||
|
|
||||||
|
# Install the CLI
|
||||||
|
echo "Installing the CLI..."
|
||||||
|
sudo install ./bin/eon /bin
|
||||||
|
echo "eon installed successfully!"
|
BIN
cmd/cmd
BIN
cmd/cmd
Binary file not shown.
446
cmd/main.go
446
cmd/main.go
|
@ -10,9 +10,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"math/big"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -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":
|
||||||
|
@ -89,8 +89,8 @@ func main() {
|
||||||
for _, pkg := range os.Args[2:] {
|
for _, pkg := range os.Args[2:] {
|
||||||
if !strings.HasPrefix(pkg, "-") {
|
if !strings.HasPrefix(pkg, "-") {
|
||||||
fileInfo, err := os.Stat(pkg)
|
fileInfo, err := os.Stat(pkg)
|
||||||
if err != nil {
|
if err != nil || fileInfo.IsDir() {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) || fileInfo.IsDir() {
|
||||||
// This unholy regex is a package name validator. It validates repository-name/package-name/1.0.0-prerelease.1+meta.1
|
// This unholy regex is a package name validator. It validates repository-name/package-name/1.0.0-prerelease.1+meta.1
|
||||||
// The regex is so unholy it breaks JetBrains' regex parser, so I had to disable it.
|
// The regex is so unholy it breaks JetBrains' regex parser, so I had to disable it.
|
||||||
//goland:noinspection RegExpUnnecessaryNonCapturingGroup
|
//goland:noinspection RegExpUnnecessaryNonCapturingGroup
|
||||||
|
@ -105,6 +105,9 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
repoPackageList = append(repoPackageList, pkg)
|
repoPackageList = append(repoPackageList, pkg)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(color.RedString("Failed to get file information: " + err.Error()))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
localPackageList = append(localPackageList, pkg)
|
localPackageList = append(localPackageList, pkg)
|
||||||
|
@ -161,7 +164,7 @@ func main() {
|
||||||
var vagueErr error
|
var vagueErr error
|
||||||
var epkBytes bytes.Buffer
|
var epkBytes bytes.Buffer
|
||||||
if !inMemoryMode {
|
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 {
|
} else {
|
||||||
_, err = io.Copy(bufio.NewWriter(&epkBytes), epkFile)
|
_, err = io.Copy(bufio.NewWriter(&epkBytes), epkFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -169,11 +172,11 @@ func main() {
|
||||||
", have you tried disabling in-memory mode?"))
|
", have you tried disabling in-memory mode?"))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err := epkFile.Close()
|
err = epkFile.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(color.HiYellowString("Failed to close package file: " + err.Error() + ", memory leak possible."))
|
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 {
|
if err != nil || vagueErr != nil {
|
||||||
common.PreMapEPKHandleError(err, vagueErr, logger)
|
common.PreMapEPKHandleError(err, vagueErr, logger)
|
||||||
|
@ -189,11 +192,15 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the architecture is supported.
|
// Check if the architecture is supported.
|
||||||
if preMap.DisplayData.Architecture != "noarch" || preMap.DisplayData.Architecture != string(uts.Machine[:]) {
|
if preMap.DisplayData.Architecture != strings.TrimRight(string(uts.Machine[:]), "\x00") {
|
||||||
fmt.Println(color.RedString("Package architecture not supported: " + preMap.DisplayData.Architecture))
|
if preMap.DisplayData.Architecture != "noarch" {
|
||||||
os.Exit(1)
|
fmt.Println(color.RedString("Package architecture not supported: " + preMap.DisplayData.Architecture))
|
||||||
|
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 = ""
|
||||||
|
@ -222,13 +229,13 @@ func main() {
|
||||||
if exists {
|
if exists {
|
||||||
if version.Compare(&preMap.DisplayData.Version) != -1 {
|
if version.Compare(&preMap.DisplayData.Version) != -1 {
|
||||||
if !forceMode {
|
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)
|
skipEpkList = append(skipEpkList, skipEpk)
|
||||||
} else {
|
} else {
|
||||||
installPackage.IsForced = true
|
installPackage.IsForced = true
|
||||||
var emptyList []string
|
var emptyList []string
|
||||||
var addedDeps int
|
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 {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -240,7 +247,7 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
var emptyList []string
|
var emptyList []string
|
||||||
var addedDeps int
|
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 {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -253,7 +260,7 @@ func main() {
|
||||||
preMap.IsUpgrade = false
|
preMap.IsUpgrade = false
|
||||||
var emptyList []string
|
var emptyList []string
|
||||||
var addedDeps int
|
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 {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -318,6 +325,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
|
||||||
|
@ -342,11 +351,14 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the total size of the package
|
// Calculate the total size of the package
|
||||||
contentLength := new(big.Int)
|
contentLength, err := strconv.ParseUint(epkBytes.Header.Get("Content-Length"), 10, 64)
|
||||||
contentLength.SetString(epkBytes.Header.Get("Content-Length"), 10)
|
if err != nil {
|
||||||
|
fmt.Println(color.RedString("Failed to get content length: " + err.Error()))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
// Print that we are downloading the package
|
// 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.
|
// Hide the cursor for reasons explained below.
|
||||||
fmt.Print("\033[?25l")
|
fmt.Print("\033[?25l")
|
||||||
|
@ -366,8 +378,8 @@ func main() {
|
||||||
// Set the progress to 100%
|
// Set the progress to 100%
|
||||||
logger.LogFunc(lib.Log{
|
logger.LogFunc(lib.Log{
|
||||||
Level: "PROGRESS",
|
Level: "PROGRESS",
|
||||||
Progress: big.NewInt(1),
|
Progress: 1,
|
||||||
Total: big.NewInt(1),
|
Total: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Show the cursor again because we're done with the progress bar.
|
// Show the cursor again because we're done with the progress bar.
|
||||||
|
@ -393,14 +405,14 @@ func main() {
|
||||||
if version.Compare(&preMap.DisplayData.Version) != -1 {
|
if version.Compare(&preMap.DisplayData.Version) != -1 {
|
||||||
// If the version is the same or newer, skip the package.
|
// If the version is the same or newer, skip the package.
|
||||||
if !forceMode {
|
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 {
|
} else {
|
||||||
// If the version is the same or newer, but the user wants to force the installation, install it.
|
// If the version is the same or newer, but the user wants to force the installation, install it.
|
||||||
epkEntry.IsForced = true
|
epkEntry.IsForced = true
|
||||||
// We can let it use our remoteEPKList to save a SQL query.
|
// We can let it use our remoteEPKList to save a SQL query.
|
||||||
var emptyList []string
|
var emptyList []string
|
||||||
var addedDeps int
|
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 {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -414,7 +426,7 @@ func main() {
|
||||||
// If the version is older, install it.
|
// If the version is older, install it.
|
||||||
var emptyList []string
|
var emptyList []string
|
||||||
var addedDeps int
|
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 {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -427,7 +439,7 @@ func main() {
|
||||||
// If the package is not installed, install it.
|
// If the package is not installed, install it.
|
||||||
var emptyList []string
|
var emptyList []string
|
||||||
var addedDeps int
|
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 {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
fmt.Println(color.RedString("Failed to handle dependencies: " + err.Error()))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -488,7 +500,7 @@ func main() {
|
||||||
} else {
|
} else {
|
||||||
finalisedList[3] = pkg.Repository.Name
|
finalisedList[3] = pkg.Repository.Name
|
||||||
}
|
}
|
||||||
finalisedList[4] = humanize.BigIBytes(pkg.EPKPreMap.DisplayData.DecompressedSize)
|
finalisedList[4] = humanize.Bytes(pkg.EPKPreMap.DisplayData.DecompressedSize)
|
||||||
if pkg.IsForced {
|
if pkg.IsForced {
|
||||||
finalisedList[5] = "Forced installation"
|
finalisedList[5] = "Forced installation"
|
||||||
} else if pkg.EPKPreMap.IsUpgrade {
|
} else if pkg.EPKPreMap.IsUpgrade {
|
||||||
|
@ -507,8 +519,8 @@ func main() {
|
||||||
}
|
}
|
||||||
fmt.Println("Transaction Summary")
|
fmt.Println("Transaction Summary")
|
||||||
fmt.Println("\nInstalling " + humanize.Comma(int64(len(epkList))) + " packages, of which " + humanize.Comma(int64(dependencies)) + " are dependencies.")
|
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 download size: " + humanize.Bytes(common.GetTotalSize(epkList)))
|
||||||
fmt.Println("Total installed size: " + humanize.BigIBytes(common.GetTotalInstalledSize(epkList)) + "\n")
|
fmt.Println("Total installed size: " + humanize.Bytes(common.GetTotalInstalledSize(epkList)) + "\n")
|
||||||
var response string
|
var response string
|
||||||
if !yesMode {
|
if !yesMode {
|
||||||
response = logger.LogFunc(lib.Log{
|
response = logger.LogFunc(lib.Log{
|
||||||
|
@ -548,8 +560,12 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start streaming the package into a buffer
|
// Start streaming the package into a buffer
|
||||||
contentLength := new(big.Int).SetBytes([]byte(epkBytes.Header.Get("Content-Length")))
|
contentLength, err := strconv.ParseUint(epkBytes.Header.Get("Content-Length"), 10, 64)
|
||||||
fmt.Println("\nDownloading package: " + installPackage.EPKPreMap.DisplayData.Name + " (" + humanize.BigIBytes(contentLength) + ")")
|
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
|
var buffer bytes.Buffer
|
||||||
_, err = io.Copy(&lib.ProgressWriter{
|
_, err = io.Copy(&lib.ProgressWriter{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
@ -564,8 +580,8 @@ func main() {
|
||||||
// Set the progress to 100%
|
// Set the progress to 100%
|
||||||
logger.LogFunc(lib.Log{
|
logger.LogFunc(lib.Log{
|
||||||
Level: "PROGRESS",
|
Level: "PROGRESS",
|
||||||
Progress: big.NewInt(1),
|
Progress: 1,
|
||||||
Total: big.NewInt(1),
|
Total: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Close the response body
|
// Close the response body
|
||||||
|
@ -637,7 +653,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)
|
||||||
|
@ -785,7 +801,7 @@ func main() {
|
||||||
finalisedList[1] = pkg.DisplayData.Architecture
|
finalisedList[1] = pkg.DisplayData.Architecture
|
||||||
finalisedList[2] = pkg.DisplayData.Version.String()
|
finalisedList[2] = pkg.DisplayData.Version.String()
|
||||||
finalisedList[3] = repositoryMap[pkg.Name].Name
|
finalisedList[3] = repositoryMap[pkg.Name].Name
|
||||||
finalisedList[4] = humanize.BigIBytes(decompressedSizeMap[pkg.Name])
|
finalisedList[4] = humanize.Bytes(decompressedSizeMap[pkg.Name])
|
||||||
finalisedList[5] = "Remove"
|
finalisedList[5] = "Remove"
|
||||||
for _, item := range finalisedList {
|
for _, item := range finalisedList {
|
||||||
common.PrintWithEvenPadding(item, maxSize)
|
common.PrintWithEvenPadding(item, maxSize)
|
||||||
|
@ -796,11 +812,11 @@ func main() {
|
||||||
}
|
}
|
||||||
fmt.Println("Transaction Summary")
|
fmt.Println("Transaction Summary")
|
||||||
fmt.Println("\nRemoving " + humanize.Comma(int64(len(packageRemoveList))) + " packages.")
|
fmt.Println("\nRemoving " + humanize.Comma(int64(len(packageRemoveList))) + " packages.")
|
||||||
space := new(big.Int)
|
var space uint64
|
||||||
for _, pkg := range packageRemoveList {
|
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{
|
response := logger.LogFunc(lib.Log{
|
||||||
Level: "INFO",
|
Level: "INFO",
|
||||||
Content: "Proceed with removal (y/n)?",
|
Content: "Proceed with removal (y/n)?",
|
||||||
|
@ -832,8 +848,31 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 < 15 {
|
||||||
|
fmt.Println(color.RedString("Terminal too small. Minimum required width: 15 characters."))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
maxWidth := width / 3
|
||||||
|
|
||||||
switch os.Args[2] {
|
switch os.Args[2] {
|
||||||
case "remote":
|
case "remote":
|
||||||
|
// Refresh the package list.
|
||||||
|
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()))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
remoteEpkList, err := common.DefaultListRemotePackagesInDB()
|
remoteEpkList, err := common.DefaultListRemotePackagesInDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(color.RedString("Failed to list remote packages: " + err.Error()))
|
fmt.Println(color.RedString("Failed to list remote packages: " + err.Error()))
|
||||||
|
@ -842,17 +881,336 @@ func main() {
|
||||||
if len(remoteEpkList) == 0 {
|
if len(remoteEpkList) == 0 {
|
||||||
fmt.Println("No remote packages.")
|
fmt.Println("No remote packages.")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Remote packages:")
|
fmt.Println("\nRemote packages:")
|
||||||
for _, epk := range remoteEpkList {
|
for range width {
|
||||||
fmt.Println("\n" + epk.Name + ":\n" +
|
fmt.Print("=")
|
||||||
"- " + 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)
|
|
||||||
}
|
}
|
||||||
|
for _, item := range []string{"Name", "Version", "Repository"} {
|
||||||
|
common.PrintWithEvenPadding(item, maxWidth)
|
||||||
|
}
|
||||||
|
for range width {
|
||||||
|
fmt.Print("=")
|
||||||
|
}
|
||||||
|
for _, epk := range remoteEpkList {
|
||||||
|
var printMap []string
|
||||||
|
printMap = append(printMap, epk.Name, epk.Version.String(), epk.Repository.Name)
|
||||||
|
for _, item := range printMap {
|
||||||
|
common.PrintWithEvenPadding(item, maxWidth)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
for range width {
|
||||||
|
fmt.Print("=")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "local":
|
||||||
|
epkMap, _, repositoryMap, _, err := common.DefaultListEPKsInDB()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(color.RedString("Failed to list installed packages: " + err.Error()))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(epkMap) == 0 {
|
||||||
|
fmt.Println("No local packages.")
|
||||||
|
} else {
|
||||||
|
// Sort the map by name.
|
||||||
|
var epkList []string
|
||||||
|
for epk := range epkMap {
|
||||||
|
epkList = append(epkList, epk)
|
||||||
|
}
|
||||||
|
sort.Strings(epkList)
|
||||||
|
fmt.Println("Local packages:")
|
||||||
|
for range width {
|
||||||
|
fmt.Print("=")
|
||||||
|
}
|
||||||
|
for _, item := range []string{"Name", "Version", "Repository"} {
|
||||||
|
common.PrintWithEvenPadding(item, maxWidth)
|
||||||
|
}
|
||||||
|
for range width {
|
||||||
|
fmt.Print("=")
|
||||||
|
}
|
||||||
|
for _, epk := range epkList {
|
||||||
|
version := epkMap[epk].Version
|
||||||
|
var printMap []string
|
||||||
|
printMap = append(printMap, epk, version.String(), repositoryMap[epk].Name)
|
||||||
|
for _, item := range printMap {
|
||||||
|
common.PrintWithEvenPadding(item, maxWidth)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
for range width {
|
||||||
|
fmt.Print("=")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.Bytes(metadata.DecompressedSize), width/2)
|
||||||
|
|
||||||
|
common.PrintWithEvenPadding("Download Size", width/2)
|
||||||
|
common.PrintWithEvenPadding(humanize.Bytes(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()
|
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.Bytes(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.")
|
||||||
|
var space uint64
|
||||||
|
for _, pkg := range removeList {
|
||||||
|
space += pkg.DisplayData.DecompressedSize
|
||||||
|
}
|
||||||
|
fmt.Println("Total reclaimed space: " + humanize.Bytes(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:
|
||||||
|
|
137
common/main.go
137
common/main.go
|
@ -19,7 +19,6 @@ import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/big"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -61,7 +60,9 @@ type Plugin struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var conn *sql.DB
|
var conn *sql.DB
|
||||||
var dbVersion = semver.MustParse("1.0.0-beta.4")
|
|
||||||
|
// Database is no longer compatible with versions below 3.0.0.
|
||||||
|
var dbVersion = semver.MustParse("3.0.0")
|
||||||
|
|
||||||
var DefaultLogger = lib.Logger{
|
var DefaultLogger = lib.Logger{
|
||||||
LogFunc: func(log lib.Log) string {
|
LogFunc: func(log lib.Log) string {
|
||||||
|
@ -80,14 +81,11 @@ var DefaultLogger = lib.Logger{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
case "PROGRESS":
|
case "PROGRESS":
|
||||||
// Maths time! We need to calculate the percentage of the progress bar.
|
// 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.
|
// Convert the total and progress to floats so we can do division.
|
||||||
floatTotal := new(big.Float)
|
var floatTotal = float64(log.Total)
|
||||||
floatProgress := new(big.Float)
|
var floatProgress = float64(log.Progress)
|
||||||
floatTotal.SetInt(log.Total)
|
// Calculate the percentage.
|
||||||
floatProgress.SetInt(log.Progress)
|
var percentage = floatProgress / floatTotal
|
||||||
// Calculate the fraction we need to multiply by 100 to get the percentage.
|
|
||||||
percentageBig := new(big.Float).Quo(floatProgress, floatTotal)
|
|
||||||
percentage, _ := percentageBig.Float64()
|
|
||||||
// Get the terminal width so we can calculate the width of the progress bar.
|
// Get the terminal width so we can calculate the width of the progress bar.
|
||||||
width, _, err := term.GetSize(int(os.Stdout.Fd()))
|
width, _, err := term.GetSize(int(os.Stdout.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -193,7 +191,7 @@ var TimeMagnitudes = []humanize.RelTimeMagnitude{
|
||||||
// End of Expat / MIT licensed code
|
// 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.
|
// Iterate through the dependencies of the target EPK.
|
||||||
dependencyLoop:
|
dependencyLoop:
|
||||||
for _, dependency := range targetEPK.EPKPreMap.DisplayData.Dependencies {
|
for _, dependency := range targetEPK.EPKPreMap.DisplayData.Dependencies {
|
||||||
|
@ -221,7 +219,7 @@ dependencyLoop:
|
||||||
// Add the dependency to the list of previous packages.
|
// Add the dependency to the list of previous packages.
|
||||||
*previousPackages = append(*previousPackages, targetEPK.EPKPreMap.DisplayData.Name)
|
*previousPackages = append(*previousPackages, targetEPK.EPKPreMap.DisplayData.Name)
|
||||||
// Recursively handle dependencies.
|
// 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
|
InstallPackageList = installedPackage
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
@ -240,7 +238,7 @@ dependencyLoop:
|
||||||
// Check if we already have a list of remote EPKs to use, if so use it.
|
// Check if we already have a list of remote EPKs to use, if so use it.
|
||||||
if len(epkList) == 0 || epkList == nil {
|
if len(epkList) == 0 || epkList == nil {
|
||||||
var err error
|
var err error
|
||||||
epkList, err = ListRemotePackagesInDB()
|
epkList, err = listRemotePackagesInDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
@ -265,7 +263,7 @@ dependencyLoop:
|
||||||
} else {
|
} else {
|
||||||
// Check if the installed version is outdated.
|
// Check if the installed version is outdated.
|
||||||
if version.LessThan(&epk.Version) {
|
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
|
remoteEPK = epk
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
|
@ -275,10 +273,27 @@ dependencyLoop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the dependency doesn't exist, crash.
|
|
||||||
if !dependencyExists {
|
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.
|
// Increase the dependency's priority.
|
||||||
epkEntry.Priority = parentPriority + 1
|
epkEntry.Priority = parentPriority + 1
|
||||||
// Add the dependency to the list of EPKs to install.
|
// Add the dependency to the list of EPKs to install.
|
||||||
|
@ -298,6 +313,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 {
|
||||||
|
@ -324,7 +340,7 @@ dependencyLoop:
|
||||||
// Add the dependency to the list of previous packages.
|
// Add the dependency to the list of previous packages.
|
||||||
*previousPackages = append(*previousPackages, epkEntry.EPKPreMap.DisplayData.Name)
|
*previousPackages = append(*previousPackages, epkEntry.EPKPreMap.DisplayData.Name)
|
||||||
// Recursively handle dependencies.
|
// 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
|
InstallPackageList = installPackages
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
@ -343,19 +359,19 @@ dependencyLoop:
|
||||||
return InstallPackageList, previousDeps, nil
|
return InstallPackageList, previousDeps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTotalSize(InstallPackageList []InstallPackage) *big.Int {
|
func GetTotalSize(InstallPackageList []InstallPackage) uint64 {
|
||||||
totalSize := new(big.Int)
|
var totalSize uint64
|
||||||
for _, epk := range InstallPackageList {
|
for _, epk := range InstallPackageList {
|
||||||
totalSize.Add(totalSize, big.NewInt(epk.EPKPreMap.DisplayData.Size))
|
totalSize += epk.EPKPreMap.DisplayData.Size
|
||||||
}
|
}
|
||||||
return totalSize
|
return totalSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTotalInstalledSize(InstallPackageList []InstallPackage) *big.Int {
|
func GetTotalInstalledSize(InstallPackageList []InstallPackage) uint64 {
|
||||||
totalSize := new(big.Int)
|
var totalSize uint64
|
||||||
for _, epk := range InstallPackageList {
|
for _, epk := range InstallPackageList {
|
||||||
if !epk.IsRemote {
|
if !epk.IsRemote {
|
||||||
totalSize.Add(totalSize, epk.EPKPreMap.DisplayData.DecompressedSize)
|
totalSize += epk.EPKPreMap.DisplayData.DecompressedSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return totalSize
|
return totalSize
|
||||||
|
@ -501,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
|
// 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 INTEGER NOT NULL)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -512,23 +528,21 @@ func InitDB(conn *sql.DB) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Exec("CREATE TABLE repositories (url TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE, owner TEXT NOT NULL, description TEXT NOT NULL)")
|
_, err = conn.Exec("CREATE TABLE repositories (url TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE, owner TEXT NOT NULL, description TEXT NOT NULL, ignore BOOLEAN NOT NULL DEFAULT false)")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, 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 {
|
if err != nil {
|
||||||
return err
|
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)")
|
_, 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 {
|
if err != nil {
|
||||||
return err
|
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)")
|
_, err = conn.Exec("CREATE TABLE global (version TEXT NOT NULL, uniquenessCheck BOOLEAN NOT NULL UNIQUE CHECK (uniquenessCheck = true) DEFAULT true)")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -654,7 +668,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 uint64, decompressedSize uint64, 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 {
|
||||||
|
@ -686,17 +700,10 @@ 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 {
|
_, err = conn.Exec("INSERT INTO packages (name, description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths, decompressedSize) 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.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, installedPathsString, decompressedSize)
|
||||||
repository[0], installedPathsString)
|
|
||||||
} else {
|
|
||||||
_, 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,
|
|
||||||
installedPathsString)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -739,11 +746,10 @@ 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, "+
|
err := conn.QueryRow("SELECT description, longDescription, version, author, license, architecture, size, dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths, decompressedSize FROM packages WHERE name = ?",
|
||||||
"dependencies, removeScript, hasRemoveScript, isDependency, repository, installedPaths 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, &metadata.DecompressedSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lib.Metadata{}, "", false, false, 0, "", nil, err
|
return lib.Metadata{}, "", false, false, 0, "", nil, err
|
||||||
}
|
}
|
||||||
|
@ -771,8 +777,8 @@ func DefaultRemoveEPKFromDB(name string) error {
|
||||||
return nil
|
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 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
|
||||||
}
|
}
|
||||||
|
@ -780,19 +786,21 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
|
||||||
repositoryMap := make(map[string]lib.Repository)
|
repositoryMap := make(map[string]lib.Repository)
|
||||||
repoNameToRepo := make(map[string]lib.Repository)
|
repoNameToRepo := make(map[string]lib.Repository)
|
||||||
metadataMap := make(map[string]lib.DisplayData)
|
metadataMap := make(map[string]lib.DisplayData)
|
||||||
sizes := make(map[string]*big.Int)
|
sizes := make(map[string]uint64)
|
||||||
compressedSizes := make(map[string]int64)
|
compressedSizes := make(map[string]uint64)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var metadata lib.DisplayData
|
var metadata lib.DisplayData
|
||||||
var size int64
|
var size uint64
|
||||||
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)
|
err := rows.Scan(&metadata.Name, &metadata.Description, &version, &metadata.Author, &metadata.Architecture,
|
||||||
|
&size, &dependencies, &repository, &isDependency, &metadata.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
|
||||||
|
@ -801,21 +809,26 @@ func DefaultListEPKsInDB() (map[string]lib.DisplayData, map[string]*big.Int, map
|
||||||
metadata.Version = *semVer
|
metadata.Version = *semVer
|
||||||
metadata.Dependencies = strings.Split(strings.TrimSuffix(strings.TrimPrefix(dependencies, "["), "]"), ", ")
|
metadata.Dependencies = strings.Split(strings.TrimSuffix(strings.TrimPrefix(dependencies, "["), "]"), ", ")
|
||||||
metadataMap[metadata.Name] = metadata
|
metadataMap[metadata.Name] = metadata
|
||||||
sizes[metadata.Name] = big.NewInt(size)
|
sizes[metadata.Name] = size
|
||||||
compressedSizes[metadata.Name] = size
|
compressedSizes[metadata.Name] = size
|
||||||
// Check if the repository is in the repoNameToRepo map
|
// Check if the repository is in the repoNameToRepo map
|
||||||
_, ok := repoNameToRepo[repository]
|
var repo lib.Repository
|
||||||
|
repo, ok := repoNameToRepo[repository]
|
||||||
if !ok {
|
if !ok {
|
||||||
// If it's not, find the repository and add it to the map
|
// If it's not, find the repository and add it to the map
|
||||||
var repo lib.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 {
|
||||||
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
repositoryMap[repository] = repo
|
repoNameToRepo[repository] = repo
|
||||||
}
|
}
|
||||||
// Add the repository to the repository map
|
// Add the repository to the repository map
|
||||||
repositoryMap[metadata.Name] = repoNameToRepo[repository]
|
repositoryMap[metadata.Name] = repo
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadataMap, sizes, repositoryMap, compressedSizes, nil
|
return metadataMap, sizes, repositoryMap, compressedSizes, nil
|
||||||
|
@ -917,7 +930,7 @@ func DefaultCheckRepositoryInDB(repository string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultListRepositoriesInDB() ([]lib.Repository, error) {
|
func DefaultListRepositoriesInDB() ([]lib.Repository, error) {
|
||||||
rows, err := conn.Query("SELECT url, name, owner, description FROM repositories")
|
rows, err := conn.Query("SELECT url, name, owner, description FROM repositories WHERE ignore = false")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []lib.Repository{}, err
|
return []lib.Repository{}, err
|
||||||
}
|
}
|
||||||
|
@ -982,7 +995,7 @@ func DefaultListRemotePackagesInDB() ([]lib.RemoteEPK, error) {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var name, author, description, version, architecture, dependencies, path, arch, repository string
|
var name, author, description, version, architecture, dependencies, path, arch, repository string
|
||||||
var hashBytes []byte
|
var hashBytes []byte
|
||||||
var size int64
|
var size uint64
|
||||||
err := rows.Scan(&name, &author, &description, &version, &architecture, &size, &dependencies, &path, &arch,
|
err := rows.Scan(&name, &author, &description, &version, &architecture, &size, &dependencies, &path, &arch,
|
||||||
&hashBytes, &repository)
|
&hashBytes, &repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
231
lib/main.go
231
lib/main.go
|
@ -15,7 +15,6 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -35,7 +34,7 @@ type RemoteEPK struct {
|
||||||
Description string
|
Description string
|
||||||
Version semver.Version
|
Version semver.Version
|
||||||
Architecture string
|
Architecture string
|
||||||
CompressedSize int64
|
CompressedSize uint64
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
Path string
|
Path string
|
||||||
Arch string
|
Arch string
|
||||||
|
@ -67,8 +66,8 @@ type Metadata struct {
|
||||||
Architecture string
|
Architecture string
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
SpecialFiles SpecialFiles
|
SpecialFiles SpecialFiles
|
||||||
Size int64
|
Size uint64
|
||||||
DecompressedSize *big.Int
|
DecompressedSize uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// EPKPreMap is a struct that contains the metadata of the EPK
|
// EPKPreMap is a struct that contains the metadata of the EPK
|
||||||
|
@ -77,7 +76,7 @@ type EPKPreMap struct {
|
||||||
MetadataMap map[string]interface{}
|
MetadataMap map[string]interface{}
|
||||||
IsLittleEndian bool
|
IsLittleEndian bool
|
||||||
IsUpgrade bool
|
IsUpgrade bool
|
||||||
TarOffset int64
|
TarOffset uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayData is a struct that contains the display data of the EPK
|
// DisplayData is a struct that contains the display data of the EPK
|
||||||
|
@ -87,9 +86,10 @@ type DisplayData struct {
|
||||||
Architecture string
|
Architecture string
|
||||||
Description string
|
Description string
|
||||||
Version semver.Version
|
Version semver.Version
|
||||||
Size int64
|
Size uint64
|
||||||
DecompressedSize *big.Int
|
DecompressedSize uint64
|
||||||
Dependencies []string
|
Dependencies []string
|
||||||
|
IsDependency bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PotentiallyNullEPKPreMap is a EPKPreMap that can be nil
|
// PotentiallyNullEPKPreMap is a EPKPreMap that can be nil
|
||||||
|
@ -104,8 +104,8 @@ type Log struct {
|
||||||
Content string
|
Content string
|
||||||
Prompt bool
|
Prompt bool
|
||||||
PlaySound bool
|
PlaySound bool
|
||||||
Progress *big.Int
|
Progress uint64
|
||||||
Total *big.Int
|
Total uint64
|
||||||
Overwrite bool
|
Overwrite bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,10 +202,12 @@ func MkdirAllWithPaths(path string, perm os.FileMode) ([]string, error) {
|
||||||
return createdDirs, nil
|
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
|
// Unmarshal the JSON
|
||||||
var displayDataMap map[string]interface{}
|
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 {
|
if err != nil {
|
||||||
return EPKPreMap{}, errors.New("metadata is not valid JSON")
|
return EPKPreMap{}, errors.New("metadata is not valid JSON")
|
||||||
}
|
}
|
||||||
|
@ -222,12 +224,14 @@ func preMapEpkFromBytes(metaDataBytes []byte, littleEndian bool, size int64, off
|
||||||
// Map the display data
|
// Map the display data
|
||||||
var ok bool
|
var ok bool
|
||||||
// Set the size
|
// Set the size
|
||||||
sizeBigInt, ok := displayDataMap["size"].(string)
|
sizeJSON, ok := displayDataMap["size"].(json.Number)
|
||||||
if !ok {
|
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
|
// Set the name, author, version, arch, and dependencies
|
||||||
parsedDisplayData.DisplayData.Name, ok = displayDataMap["name"].(string)
|
parsedDisplayData.DisplayData.Name, ok = displayDataMap["name"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -263,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
|
// 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 ErrPreMapEPKCouldNotRead = errors.New("could not read EPK")
|
||||||
var ErrPreMapEPKHasNetworkStream = errors.New("network streams are not supported")
|
var ErrPreMapEPKHasNetworkStream = errors.New("network streams are not supported")
|
||||||
|
@ -272,7 +276,7 @@ var ErrPreMapEPKHasInvalidEndian = errors.New("has invalid endian")
|
||||||
var ErrPreMapEPKCouldNotMapJSON = errors.New("could not map metadata")
|
var ErrPreMapEPKCouldNotMapJSON = errors.New("could not map metadata")
|
||||||
|
|
||||||
// PreMapEPK maps enough data to create the display summary of an EPK
|
// 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
|
// Say that we don't support network streams
|
||||||
if epkBytes.IsURL {
|
if epkBytes.IsURL {
|
||||||
return EPKPreMap{}, nil, ErrPreMapEPKHasNetworkStream
|
return EPKPreMap{}, nil, ErrPreMapEPKHasNetworkStream
|
||||||
|
@ -320,7 +324,7 @@ func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can get the offsets of the tar archive
|
// Now we can get the offsets of the tar archive
|
||||||
var tarArchiveOffset int64
|
var tarArchiveOffset uint64
|
||||||
if epkBytes.IsFileStream {
|
if epkBytes.IsFileStream {
|
||||||
var tarArchiveOffsetBytes = make([]byte, 8)
|
var tarArchiveOffsetBytes = make([]byte, 8)
|
||||||
_, err := epkBytes.FileStream.ReadAt(tarArchiveOffsetBytes, 4)
|
_, err := epkBytes.FileStream.ReadAt(tarArchiveOffsetBytes, 4)
|
||||||
|
@ -328,15 +332,15 @@ func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error)
|
||||||
return EPKPreMap{}, err, ErrPreMapEPKCouldNotRead
|
return EPKPreMap{}, err, ErrPreMapEPKCouldNotRead
|
||||||
}
|
}
|
||||||
if littleEndian {
|
if littleEndian {
|
||||||
tarArchiveOffset = int64(binary.LittleEndian.Uint64(tarArchiveOffsetBytes))
|
tarArchiveOffset = binary.LittleEndian.Uint64(tarArchiveOffsetBytes)
|
||||||
} else {
|
} else {
|
||||||
tarArchiveOffset = int64(binary.BigEndian.Uint64(tarArchiveOffsetBytes))
|
tarArchiveOffset = binary.BigEndian.Uint64(tarArchiveOffsetBytes)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if littleEndian {
|
if littleEndian {
|
||||||
tarArchiveOffset = int64(binary.LittleEndian.Uint64(epkBytes.Bytes[4:12]))
|
tarArchiveOffset = binary.LittleEndian.Uint64(epkBytes.Bytes[4:12])
|
||||||
} else {
|
} else {
|
||||||
tarArchiveOffset = int64(binary.BigEndian.Uint64(epkBytes.Bytes[4:12]))
|
tarArchiveOffset = binary.BigEndian.Uint64(epkBytes.Bytes[4:12])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,11 +349,14 @@ func PreMapEPK(epkBytes StreamOrBytes, epkSize int64) (EPKPreMap, error, error)
|
||||||
var preMapEpk EPKPreMap
|
var preMapEpk EPKPreMap
|
||||||
if epkBytes.IsFileStream {
|
if epkBytes.IsFileStream {
|
||||||
var metadataBuffer = make([]byte, tarArchiveOffset-ConstMapEPKMetadataOffset)
|
var metadataBuffer = make([]byte, tarArchiveOffset-ConstMapEPKMetadataOffset)
|
||||||
_, err := epkBytes.FileStream.ReadAt(metadataBuffer, ConstMapEPKMetadataOffset)
|
_, err := epkBytes.FileStream.ReadAt(metadataBuffer, int64(ConstMapEPKMetadataOffset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return EPKPreMap{}, err, ErrPreMapEPKCouldNotRead
|
return EPKPreMap{}, err, ErrPreMapEPKCouldNotRead
|
||||||
}
|
}
|
||||||
preMapEpk, err = preMapEpkFromBytes(metadataBuffer, littleEndian, epkSize, tarArchiveOffset)
|
preMapEpk, err = preMapEpkFromBytes(metadataBuffer, littleEndian, epkSize, tarArchiveOffset)
|
||||||
|
if err != nil {
|
||||||
|
return EPKPreMap{}, err, ErrPreMapEPKCouldNotMapJSON
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
preMapEpk, err = preMapEpkFromBytes(epkBytes.Bytes[ConstMapEPKMetadataOffset:tarArchiveOffset], littleEndian, epkSize, tarArchiveOffset)
|
preMapEpk, err = preMapEpkFromBytes(epkBytes.Bytes[ConstMapEPKMetadataOffset:tarArchiveOffset], littleEndian, epkSize, tarArchiveOffset)
|
||||||
|
@ -423,6 +430,9 @@ func PreMapRemoteEPK(remoteEPK RemoteEPK, logger *Logger) (EPKPreMap, error, err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return EPKPreMap{}, err, ErrPreMapRemoteEPKCouldNotCloseConnection
|
return EPKPreMap{}, err, ErrPreMapRemoteEPKCouldNotCloseConnection
|
||||||
}
|
}
|
||||||
|
} else if resp.StatusCode == 404 {
|
||||||
|
// Repository not found
|
||||||
|
return EPKPreMap{}, errors.New("repository not found: " + strconv.Itoa(resp.StatusCode)), ErrPreMapRemoteEPKUnexpectedStatusCode
|
||||||
} else {
|
} else {
|
||||||
// Something went wrong
|
// Something went wrong
|
||||||
return EPKPreMap{}, errors.New("unexpected status code: " + strconv.Itoa(resp.StatusCode)), ErrPreMapRemoteEPKUnexpectedStatusCode
|
return EPKPreMap{}, errors.New("unexpected status code: " + strconv.Itoa(resp.StatusCode)), ErrPreMapRemoteEPKUnexpectedStatusCode
|
||||||
|
@ -444,11 +454,11 @@ func PreMapRemoteEPK(remoteEPK RemoteEPK, logger *Logger) (EPKPreMap, error, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can get the offsets of the tar archive
|
// Now we can get the offsets of the tar archive
|
||||||
var tarArchiveOffset int64
|
var tarArchiveOffset uint64
|
||||||
if littleEndian {
|
if littleEndian {
|
||||||
tarArchiveOffset = int64(binary.LittleEndian.Uint64(epkHeaderBytes[4:12]))
|
tarArchiveOffset = binary.LittleEndian.Uint64(epkHeaderBytes[4:12])
|
||||||
} else {
|
} else {
|
||||||
tarArchiveOffset = int64(binary.BigEndian.Uint64(epkHeaderBytes[4:12]))
|
tarArchiveOffset = binary.BigEndian.Uint64(epkHeaderBytes[4:12])
|
||||||
}
|
}
|
||||||
|
|
||||||
// No signature verification for you
|
// No signature verification for you
|
||||||
|
@ -457,7 +467,7 @@ func PreMapRemoteEPK(remoteEPK RemoteEPK, logger *Logger) (EPKPreMap, error, err
|
||||||
displayDataBytes := make([]byte, tarArchiveOffset-ConstMapEPKMetadataOffset)
|
displayDataBytes := make([]byte, tarArchiveOffset-ConstMapEPKMetadataOffset)
|
||||||
if rangeSupported {
|
if rangeSupported {
|
||||||
// Send another request to fetch the display data
|
// 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)
|
resp, err = http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return EPKPreMap{}, err, ErrPreMapRemoteEPKCouldNotSendRequest
|
return EPKPreMap{}, err, ErrPreMapRemoteEPKCouldNotSendRequest
|
||||||
|
@ -689,7 +699,7 @@ func FullyMapMetadata(epkBytes StreamOrBytes, preMap *EPKPreMap, checkFingerprin
|
||||||
if epkBytes.IsFileStream {
|
if epkBytes.IsFileStream {
|
||||||
// Now we can verify the signature. First, we need to take the checksum of the metadata
|
// 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
|
// 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 {
|
if err != nil {
|
||||||
return &Metadata{}, err, ErrFullyMapMetadataCouldNotJump
|
return &Metadata{}, err, ErrFullyMapMetadataCouldNotJump
|
||||||
}
|
}
|
||||||
|
@ -788,12 +798,14 @@ func FullyMapMetadata(epkBytes StreamOrBytes, preMap *EPKPreMap, checkFingerprin
|
||||||
if !ok {
|
if !ok {
|
||||||
return &Metadata{}, errors.New("license is not a string"), ErrFullyMapMetadataCouldNotMapJSON
|
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 {
|
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
|
return &parsedMetadata, nil, nil
|
||||||
}
|
}
|
||||||
|
@ -814,15 +826,15 @@ var ErrInstallEPKCouldNotRemoveTempDir = errors.New("could not remove temporary
|
||||||
// ProgressWriter implements a writer that intercepts writes in order to log progress
|
// ProgressWriter implements a writer that intercepts writes in order to log progress
|
||||||
type ProgressWriter struct {
|
type ProgressWriter struct {
|
||||||
Logger *Logger
|
Logger *Logger
|
||||||
Total *big.Int
|
Total uint64
|
||||||
Writer io.Writer
|
Writer io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes to the ProgressWriter
|
// Write writes to the ProgressWriter
|
||||||
func (writer *ProgressWriter) Write(p []byte) (n int, err error) {
|
func (writer *ProgressWriter) Write(p []byte) (n int, err error) {
|
||||||
byteCount := new(big.Int)
|
var byteCount uint64
|
||||||
for range p {
|
for range p {
|
||||||
byteCount.Add(byteCount, big.NewInt(1))
|
byteCount++
|
||||||
}
|
}
|
||||||
if writer.Logger.ProgressSupported {
|
if writer.Logger.ProgressSupported {
|
||||||
writer.Logger.LogFunc(Log{
|
writer.Logger.LogFunc(Log{
|
||||||
|
@ -834,7 +846,7 @@ func (writer *ProgressWriter) Write(p []byte) (n int, err error) {
|
||||||
} else {
|
} else {
|
||||||
writer.Logger.LogFunc(Log{
|
writer.Logger.LogFunc(Log{
|
||||||
Level: "INFO",
|
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,
|
Prompt: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -848,7 +860,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, uint64, uint64, 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 {
|
||||||
|
@ -859,7 +871,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
var connection io.ReadCloser
|
var connection io.ReadCloser
|
||||||
if epkBytes.IsFileStream {
|
if epkBytes.IsFileStream {
|
||||||
// Seek to the correct position in the EPK
|
// 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 {
|
if err != nil {
|
||||||
return "", err, nil
|
return "", err, nil
|
||||||
}
|
}
|
||||||
|
@ -876,7 +888,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
return tempDir, err, ErrInstallEPKCouldNotCreateZStandardReader
|
return tempDir, err, ErrInstallEPKCouldNotCreateZStandardReader
|
||||||
}
|
}
|
||||||
// Set the range header
|
// 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
|
// Send the request
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -891,9 +903,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
|
// God this is painful. Let's give the user a progress bar to make it less painful
|
||||||
_, err := io.CopyN(&ProgressWriter{
|
_, err := io.CopyN(&ProgressWriter{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
Total: big.NewInt(preMap.TarOffset),
|
Total: preMap.TarOffset,
|
||||||
Writer: io.Discard,
|
Writer: io.Discard,
|
||||||
}, connection, preMap.TarOffset)
|
}, connection, int64(preMap.TarOffset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
|
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
|
||||||
}
|
}
|
||||||
|
@ -918,7 +930,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
tarReader := tar.NewReader(zStandardReader)
|
tarReader := tar.NewReader(zStandardReader)
|
||||||
|
|
||||||
// Create a goroutine to see how much of the decompressed size we have decompressed
|
// 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)
|
stop := make(chan bool)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -936,7 +948,7 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
} else {
|
} else {
|
||||||
logger.LogFunc(Log{
|
logger.LogFunc(Log{
|
||||||
Level: "INFO",
|
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,
|
Prompt: false,
|
||||||
})
|
})
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
@ -1066,19 +1078,12 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
|
return tempDir, err, ErrInstallEPKCouldNotDecompressTarArchive
|
||||||
}
|
}
|
||||||
|
|
||||||
written.Add(written, big.NewInt(writtenFile))
|
written += uint64(writtenFile)
|
||||||
|
|
||||||
err = file.Close()
|
err = file.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tempDir, err, ErrInstallEPKCouldNotCloseTarReader
|
return tempDir, err, ErrInstallEPKCouldNotCloseTarReader
|
||||||
} else {
|
} 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 {
|
if !isHook {
|
||||||
// Add the file to the installed files
|
// Add the file to the installed files
|
||||||
installedFiles = append(installedFiles, target)
|
installedFiles = append(installedFiles, target)
|
||||||
|
@ -1098,6 +1103,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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1189,24 +1296,24 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
file, err := os.ReadFile(filepath.Join(tempDir, "hooks", "remove.sh"))
|
file, err := os.ReadFile(filepath.Join(tempDir, "hooks", "remove.sh"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB
|
||||||
|
} else {
|
||||||
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, "Local file")
|
||||||
} 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
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return tempDir, err, ErrInstallEPKCouldNotAddEPKToDB
|
|
||||||
}
|
}
|
||||||
} 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, "Local file")
|
||||||
} 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
|
||||||
|
@ -1222,8 +1329,8 @@ func InstallEPK(epkBytes StreamOrBytes, metadata *Metadata, preMap *EPKPreMap, a
|
||||||
stop <- true
|
stop <- true
|
||||||
logger.LogFunc(Log{
|
logger.LogFunc(Log{
|
||||||
Level: "PROGRESS",
|
Level: "PROGRESS",
|
||||||
Progress: big.NewInt(1),
|
Progress: 1,
|
||||||
Total: big.NewInt(1),
|
Total: 1,
|
||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1413,12 +1520,12 @@ func AddRepository(url string, addRepositoryToDB func(Repository, bool) error, g
|
||||||
return "", errors.New("package version is not a valid semver version"), ErrAddRepositoryHasInvalidMetadata
|
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 {
|
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 {
|
if err != nil {
|
||||||
return "", errors.New("package size is not a number"), ErrAddRepositoryHasInvalidMetadata
|
return "", errors.New("package size is not a number"), ErrAddRepositoryHasInvalidMetadata
|
||||||
}
|
}
|
||||||
|
|
9
main.go
Normal file
9
main.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("Run the makefile to build the project, not go build")
|
||||||
|
}
|
Loading…
Reference in a new issue