Skip to content

Commit

Permalink
feat: make curl progress bar correctly shows on the gui
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Yu <jack.yu@suse.com>
  • Loading branch information
Yu-Jack committed Nov 13, 2024
1 parent 9e1027f commit 918d5a7
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 4 deletions.
16 changes: 15 additions & 1 deletion package/harvester-os/files/usr/sbin/harv-install
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,21 @@ get_url()
attempts=5
until [ "$n" -ge "$attempts" ]
do
curl -o $TO -fL ${FROM} && break
# Because `curl` command uses `\r` to overwrite the progress bar,
# so we should also consider `\r` when splitting the output.
# Hence, we use `startcurl` and `endcurl` to trigger replacing the progress bar.
# But, when we use `\r` to display, the header will be overwritten, so we need to print the header manually.
echo "% Total % Received % Xferd Average Speed Time Time Time Current"
echo " Dload Upload Total Spent Left Speed"
echo "startcurl"
curl -o $TO -fL ${FROM} 2>&1
curl_result=$?
echo "endcurl"

if [ "$curl_result" -eq 0 ]; then
break
fi

n=$((n+1))
echo "Failed to download, retry attempt ${n} out of ${attempts}"
sleep 2
Expand Down
74 changes: 71 additions & 3 deletions pkg/console/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package console

import (
"bufio"
"bytes"
"context"
"crypto/tls"
"encoding/binary"
Expand Down Expand Up @@ -396,12 +397,59 @@ func execute(ctx context.Context, g *gocui.Gui, env []string, cmdName string) er
return cmd.Wait()
}

func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0 : len(data)-1]
}
return data
}

func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}

if i := bytes.IndexByte(data, '\n'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, dropCR(data[0:i]), nil
}

if i := bytes.IndexByte(data, '\r'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, dropCR(data[0:i]), nil
}

// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), dropCR(data), nil
}
// Request more data.
return 0, nil, nil
}

func printToPanelAndLog(g *gocui.Gui, panel string, logPrefix string, reader io.Reader, lock *sync.Mutex) {
scanner := bufio.NewScanner(reader)
scanner.Split(ScanLines)
currentPrinter := printToPanel

for scanner.Scan() {
logrus.Infof("%s: %s", logPrefix, scanner.Text())
lock.Lock()
printToPanel(g, scanner.Text(), panel)
text := scanner.Text()

if strings.Contains(text, "startcurl") {
currentPrinter = printCurlProgressBarToPanel
lock.Unlock()
continue
}
if strings.Contains(text, "endcurl") {
currentPrinter = printToPanel
printToPanel(g, " ", panel)
lock.Unlock()
continue
}

currentPrinter(g, text, panel)
lock.Unlock()
}
}
Expand Down Expand Up @@ -581,12 +629,10 @@ func doUpgrade(g *gocui.Gui) error {
}

scanner := bufio.NewScanner(stdout)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
printToPanel(g, scanner.Text(), upgradePanel)
}
scanner = bufio.NewScanner(stderr)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
printToPanel(g, scanner.Text(), upgradePanel)
}
Expand Down Expand Up @@ -615,6 +661,28 @@ func printToPanel(g *gocui.Gui, message string, panelName string) {
<-ch
}

func printCurlProgressBarToPanel(g *gocui.Gui, message string, panelName string) {
// block printToPanel call in the same goroutine.
// This ensures messages are printed out in the calling order.
ch := make(chan struct{})

g.Update(func(g *gocui.Gui) error {

defer func() {
ch <- struct{}{}
}()

v, err := g.View(panelName)
if err != nil {
return err
}
v.Write(append([]byte{'\r'}, []byte(message)...))
return nil
})

<-ch
}

func getRemoteConfig(configURL string) (*config.HarvesterConfig, error) {
client := newProxyClient()
b, err := getURL(client, configURL)
Expand Down

0 comments on commit 918d5a7

Please sign in to comment.