zenity/internal/zenutil/progress_unix.go

121 lines
2.1 KiB
Go
Raw Normal View History

2022-03-24 10:37:37 -04:00
//go:build !windows
2021-04-25 19:36:15 -04:00
package zenutil
import (
2021-04-30 14:19:14 -04:00
"bytes"
2021-04-30 14:05:49 -04:00
"context"
2022-07-27 19:11:12 -04:00
"fmt"
2021-04-30 14:05:49 -04:00
"io"
"os"
"os/exec"
"runtime"
2021-04-25 19:36:15 -04:00
"strconv"
2021-04-30 14:05:49 -04:00
"sync/atomic"
"time"
2021-04-25 19:36:15 -04:00
)
type progressDialog struct {
2021-04-30 14:05:49 -04:00
ctx context.Context
cmd *exec.Cmd
2021-04-25 19:36:15 -04:00
max int
2021-04-30 14:05:49 -04:00
percent bool
closed int32
lines chan string
done chan struct{}
err error
2021-04-25 19:36:15 -04:00
}
2021-04-29 11:05:28 -04:00
func (d *progressDialog) send(line string) error {
2021-04-25 19:36:15 -04:00
select {
2021-04-29 11:05:28 -04:00
case d.lines <- line:
2021-04-25 19:36:15 -04:00
return nil
2021-04-29 11:05:28 -04:00
case <-d.done:
return d.err
2021-04-25 19:36:15 -04:00
}
}
2021-04-29 11:05:28 -04:00
func (d *progressDialog) Text(text string) error {
return d.send("#" + text)
2021-04-25 19:36:15 -04:00
}
2021-04-29 11:05:28 -04:00
func (d *progressDialog) Value(value int) error {
if d.percent {
return d.send(strconv.FormatFloat(100*float64(value)/float64(d.max), 'f', -1, 64))
2021-04-25 19:36:15 -04:00
} else {
2021-04-29 11:05:28 -04:00
return d.send(strconv.Itoa(value))
2021-04-25 19:36:15 -04:00
}
}
2021-04-29 11:05:28 -04:00
func (d *progressDialog) MaxValue() int {
return d.max
2021-04-25 19:36:15 -04:00
}
2021-04-29 11:05:28 -04:00
func (d *progressDialog) Done() <-chan struct{} {
return d.done
2021-04-25 19:36:15 -04:00
}
2021-04-30 14:05:49 -04:00
func (d *progressDialog) Complete() error {
2021-04-30 14:19:14 -04:00
err := d.Value(d.max)
2021-04-30 14:05:49 -04:00
close(d.lines)
2021-04-30 14:19:14 -04:00
return err
2021-04-30 14:05:49 -04:00
}
func (d *progressDialog) Close() error {
atomic.StoreInt32(&d.closed, 1)
d.cmd.Process.Signal(os.Interrupt)
<-d.done
return d.err
}
2021-04-30 14:19:14 -04:00
func (d *progressDialog) wait(extra *string, out *bytes.Buffer) {
2021-04-30 14:05:49 -04:00
err := d.cmd.Wait()
if cerr := d.ctx.Err(); cerr != nil {
err = cerr
}
if eerr, ok := err.(*exec.ExitError); ok {
switch {
case eerr.ExitCode() == -1 && atomic.LoadInt32(&d.closed) != 0:
err = nil
case eerr.ExitCode() == 1:
2022-07-27 19:11:12 -04:00
out := bytes.TrimSuffix(out.Bytes(), []byte{'\n'})
if extra != nil && *extra == string(out) {
2021-04-30 14:19:14 -04:00
err = ErrExtraButton
} else {
err = ErrCanceled
}
2022-07-27 19:11:12 -04:00
default:
err = fmt.Errorf("%w: %s", eerr, eerr.Stderr)
2021-04-30 14:05:49 -04:00
}
}
d.err = err
close(d.done)
}
func (d *progressDialog) pipe(w io.WriteCloser) {
defer w.Close()
var timeout = time.Second
if runtime.GOOS == "darwin" {
timeout = 40 * time.Millisecond
}
for {
var line string
select {
case s, ok := <-d.lines:
if !ok {
return
}
line = s
case <-d.ctx.Done():
return
2021-04-30 14:19:14 -04:00
case <-d.done:
return
2021-04-30 14:05:49 -04:00
case <-time.After(timeout):
2021-04-30 14:19:14 -04:00
// line = ""
2021-04-30 14:05:49 -04:00
}
if _, err := w.Write([]byte(line + "\n")); err != nil {
return
}
}
}