zenity/internal/zenutil/run_progress.go

113 lines
1.8 KiB
Go
Raw Normal View History

2021-04-25 19:36:15 -04:00
// +build !windows,!js
package zenutil
import (
2021-04-30 14:05:49 -04:00
"context"
"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 {
close(d.lines)
select {
case <-d.done:
return d.err
default:
return nil
}
}
func (d *progressDialog) Close() error {
atomic.StoreInt32(&d.closed, 1)
d.cmd.Process.Signal(os.Interrupt)
<-d.done
return d.err
}
func (d *progressDialog) wait() {
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:
err = Canceled
}
}
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
case <-time.After(timeout):
}
if _, err := w.Write([]byte(line + "\n")); err != nil {
return
}
}
}