mirror of
https://github.com/EnumeratedDev/bpm.git
synced 2026-09-16 10:36:12 +00:00
Add progress bars
This commit is contained in:
@@ -343,7 +343,7 @@ func CompileSourcePackage(archiveFilename, outputDirectory string, skipChecks, k
|
||||
}
|
||||
|
||||
func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string, verbose bool) error {
|
||||
for _, download := range pkgInfo.Downloads {
|
||||
for i, download := range pkgInfo.Downloads {
|
||||
// Replace variables
|
||||
replaceVars := func(s string) string {
|
||||
switch s {
|
||||
@@ -387,7 +387,7 @@ func downloadPackageFiles(pkgInfo *PackageInfo, tempDirectory string, verbose bo
|
||||
filepath = path.Join(tempDirectory, download.Filepath)
|
||||
}
|
||||
|
||||
err := downloadFile(downloadUrl, filepath, 0644)
|
||||
err := downloadFile("Downloading file "+strconv.Itoa(i+1), downloadUrl, filepath, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+25
-4
@@ -1,9 +1,13 @@
|
||||
package bpmlib
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
@@ -135,13 +139,30 @@ func (db *configDatabase) SyncLocalDatabaseFile() error {
|
||||
}
|
||||
|
||||
// Retrieve data from URL
|
||||
buffer, err := retrieveUrlData(u)
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Create progress bar
|
||||
bar := createProgressBar(resp.ContentLength, "Syncing "+db.Name, false)
|
||||
|
||||
// Copy data
|
||||
var buffer bytes.Buffer
|
||||
bufferWriter := bufio.NewWriter(&buffer)
|
||||
_, err = io.Copy(io.MultiWriter(bufferWriter, bar), resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmarshal data to ensure it is a valid BPM database
|
||||
err = yaml.Unmarshal(buffer, &BPMDatabase{})
|
||||
err = yaml.Unmarshal(buffer.Bytes(), &BPMDatabase{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not decode database: %s", err)
|
||||
}
|
||||
@@ -159,7 +180,7 @@ func (db *configDatabase) SyncLocalDatabaseFile() error {
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = out.Write(buffer)
|
||||
_, err = out.Write(buffer.Bytes())
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -244,7 +265,7 @@ func (db *BPMDatabase) FetchPackage(pkg string) (string, error) {
|
||||
}
|
||||
|
||||
// Download package from url
|
||||
err = downloadFile(u, path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), 0644)
|
||||
err = downloadFile("Downloading "+entry.Info.Name, u, path.Join("/var/cache/bpm/fetched/", path.Base(entry.Filepath)), 0644)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
+9
-1
@@ -1,9 +1,17 @@
|
||||
module git.enumerated.dev/bubble-package-manager/bpm/src/bpmlib
|
||||
|
||||
go 1.23
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/drone/envsubst v1.0.3
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f
|
||||
github.com/schollz/progressbar/v3 v3.18.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
||||
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g=
|
||||
github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
||||
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
+13
-16
@@ -9,29 +9,22 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func retrieveUrlData(u string) ([]byte, error) {
|
||||
resp, err := http.Get(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Load data into byte buffer
|
||||
buffer, err := io.ReadAll(resp.Body)
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
func downloadFile(u, filepath string, perm os.FileMode) error {
|
||||
func downloadFile(barText, u, filepath string, perm os.FileMode) error {
|
||||
if strings.HasSuffix(filepath, "/") {
|
||||
return fmt.Errorf("Filepath must not end in '/'")
|
||||
}
|
||||
|
||||
data, err := retrieveUrlData(u)
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Create parent directories
|
||||
err = os.MkdirAll(path.Dir(filepath), 0755)
|
||||
if err != nil {
|
||||
@@ -45,8 +38,12 @@ func downloadFile(u, filepath string, perm os.FileMode) error {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Create progress bar
|
||||
bar := createProgressBar(resp.ContentLength, barText, false)
|
||||
defer bar.Close()
|
||||
|
||||
// Copy data
|
||||
_, err = file.Write(data)
|
||||
_, err = io.Copy(io.MultiWriter(file, bar), resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -478,7 +478,7 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
||||
var bpmpkg *BPMPackage
|
||||
|
||||
// Check if package has already been fetched from download link
|
||||
if _, ok := fetchedPackages[entry.Filepath]; !ok {
|
||||
if fetchedFilepath, ok := fetchedPackages[entry.Filepath]; !ok {
|
||||
// Fetch package from database
|
||||
fetchedPackage, err := entry.Database.FetchPackage(entry.Info.Name)
|
||||
if err != nil {
|
||||
@@ -493,16 +493,22 @@ func (operation *BPMOperation) FetchPackages() (err error) {
|
||||
|
||||
// Add fetched package to map
|
||||
fetchedPackages[entry.Filepath] = fetchedPackage
|
||||
|
||||
fmt.Printf("Package (%s) was successfully fetched!\n", entry.Info.Name)
|
||||
} else {
|
||||
// Read fetched package
|
||||
bpmpkg, err = ReadPackage(fetchedPackages[entry.Filepath])
|
||||
bpmpkg, err = ReadPackage(fetchedFilepath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read package (%s): %s\n", entry.Info.Name, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Package (%s) was successfully fetched!\n", entry.Info.Name)
|
||||
// Get size of fetched archive
|
||||
stat, err := os.Stat(fetchedFilepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bar := createProgressBar(stat.Size(), "Downloading "+entry.Info.Name, false)
|
||||
bar.Set64(stat.Size())
|
||||
bar.Close()
|
||||
}
|
||||
|
||||
if bpmpkg.PkgInfo.IsSplitPackage() {
|
||||
@@ -622,8 +628,6 @@ func (operation *BPMOperation) Execute(verbose, force bool) (err error) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not set installation reason for package (%s): %s\n", value.BpmPackage.PkgInfo.Name, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Package (%s) was successfully installed\n", bpmpkg.PkgInfo.Name)
|
||||
}
|
||||
}
|
||||
fmt.Println("Operation complete!")
|
||||
|
||||
+17
-1
@@ -601,6 +601,10 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize progress bar
|
||||
bar := createProgressBar(int64(bpmpkg.GetInstalledSize()), "Installing "+bpmpkg.PkgInfo.Name, verbose)
|
||||
defer bar.Close()
|
||||
|
||||
tarballFile, err := readTarballFile(filename, "files.tar.gz")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -612,6 +616,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
return err
|
||||
}
|
||||
packageFilesReader := tar.NewReader(archive)
|
||||
|
||||
for {
|
||||
header, err := packageFilesReader.Next()
|
||||
if err == io.EOF {
|
||||
@@ -648,6 +653,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
if verbose {
|
||||
fmt.Printf("Created directory %s (%o)\n", extractFilename, header.Mode)
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
case tar.TypeReg:
|
||||
skip := false
|
||||
if _, err := os.Stat(extractFilename); err == nil {
|
||||
@@ -704,6 +710,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
if verbose {
|
||||
fmt.Printf("Created File: %s (%o)\n", extractFilename, header.Mode)
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
case tar.TypeSymlink:
|
||||
err := os.Remove(extractFilename)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
@@ -718,6 +725,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
if verbose {
|
||||
fmt.Println("Created Symlink: " + extractFilename + " -> " + header.Linkname)
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
case tar.TypeLink:
|
||||
if verbose {
|
||||
fmt.Println("Detected Hard Link: " + extractFilename + " -> " + path.Join(rootDir, strings.TrimPrefix(header.Linkname, "files/")))
|
||||
@@ -727,6 +735,7 @@ func extractPackage(bpmpkg *BPMPackage, verbose bool, filename, rootDir string)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
bar.Add64(header.Size)
|
||||
default:
|
||||
return errors.New("unknown type (" + strconv.Itoa(int(header.Typeflag)) + ") in " + extractFilename)
|
||||
}
|
||||
@@ -979,8 +988,11 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
||||
log.Printf("Warning: %s\n", err)
|
||||
}
|
||||
|
||||
// Get BPM package
|
||||
bpmpkg := GetPackage(pkg, rootDir)
|
||||
|
||||
// Fetching and reversing package file entry list
|
||||
fileEntries := GetPackage(pkg, rootDir).PkgFiles
|
||||
fileEntries := bpmpkg.PkgFiles
|
||||
sort.Slice(fileEntries, func(i, j int) bool {
|
||||
return fileEntries[i].Path < fileEntries[j].Path
|
||||
})
|
||||
@@ -990,8 +1002,12 @@ func removePackage(pkg string, verbose bool, rootDir string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
bar := createProgressBar(int64(bpmpkg.GetInstalledSize()), "Removing "+bpmpkg.PkgInfo.Name, verbose)
|
||||
defer bar.Close()
|
||||
|
||||
// Removing package files
|
||||
for _, entry := range fileEntries {
|
||||
bar.Add64(int64(entry.SizeInBytes))
|
||||
file := path.Join(rootDir, entry.Path)
|
||||
lstat, err := os.Lstat(file)
|
||||
if os.IsNotExist(err) {
|
||||
|
||||
@@ -2,10 +2,14 @@ package bpmlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/schollz/progressbar/v3"
|
||||
)
|
||||
|
||||
type BPMLock struct {
|
||||
@@ -64,6 +68,30 @@ func GetArch() string {
|
||||
return string(byteString[:indexLength])
|
||||
}
|
||||
|
||||
func createProgressBar(max int64, description string, hideBar bool) *progressbar.ProgressBar {
|
||||
var output io.Writer
|
||||
if hideBar {
|
||||
output = io.Discard
|
||||
} else {
|
||||
output = os.Stderr
|
||||
}
|
||||
|
||||
return progressbar.NewOptions64(max,
|
||||
progressbar.OptionSetDescription(description),
|
||||
progressbar.OptionSetWriter(output),
|
||||
progressbar.OptionShowBytes(true),
|
||||
progressbar.OptionShowTotalBytes(true),
|
||||
progressbar.OptionSetWidth(20),
|
||||
progressbar.OptionThrottle(65*time.Millisecond),
|
||||
progressbar.OptionShowCount(),
|
||||
progressbar.OptionOnCompletion(func() {
|
||||
fmt.Fprint(output, "\n")
|
||||
}),
|
||||
progressbar.OptionSpinnerType(14),
|
||||
progressbar.OptionSetRenderBlankState(true),
|
||||
progressbar.OptionSetTheme(progressbar.ThemeASCII))
|
||||
}
|
||||
|
||||
func stringSliceRemove(s []string, r string) []string {
|
||||
for i, v := range s {
|
||||
if v == r {
|
||||
|
||||
Reference in New Issue
Block a user