WIP: progress (macOS).
This commit is contained in:
parent
02bbc4741c
commit
c74a75a4ca
5 changed files with 171 additions and 15 deletions
|
@ -49,3 +49,23 @@ var app=Application.currentApplication()
|
|||
app.includeStandardAdditions=true
|
||||
void app.displayNotification({{json .Text}},{{json .Options}})
|
||||
{{- end}}`))
|
||||
|
||||
var progress =`
|
||||
var app=Application.currentApplication()
|
||||
app.includeStandardAdditions=true
|
||||
app.activate()
|
||||
ObjC.import('stdlib')
|
||||
ObjC.import('readline')
|
||||
function run(args){Progress.totalUnitCount=100
|
||||
Progress.completedUnitCount=0
|
||||
Progress.description=args[0]||"Progress"
|
||||
Progress.additionalDescription=args[1]||"Running..."
|
||||
while(true){var s
|
||||
try{s=$.readline('')}catch(e){if(e.errorNumber===-128)$.exit(1)
|
||||
break}
|
||||
if(s.indexOf('#')===0){Progress.additionalDescription=s.slice(1).trim()
|
||||
continue}
|
||||
var i=parseInt(s)
|
||||
if(Number.isSafeInteger(i)){Progress.completedUnitCount=i
|
||||
continue}}
|
||||
Progress.completedUnitCount=100}`
|
||||
|
|
|
@ -4,7 +4,6 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -17,21 +16,21 @@ import (
|
|||
func main() {
|
||||
dir := os.Args[1]
|
||||
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
files, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var args struct {
|
||||
Templates string
|
||||
Progress string
|
||||
}
|
||||
|
||||
var str strings.Builder
|
||||
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
|
||||
str.WriteString("\n" + `{{define "`)
|
||||
str.WriteString(strings.TrimSuffix(name, filepath.Ext(name)))
|
||||
str.WriteString(`" -}}` + "\n")
|
||||
|
||||
data, err := ioutil.ReadFile(filepath.Join(dir, name))
|
||||
data, err := os.ReadFile(filepath.Join(dir, name))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -40,8 +39,16 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
str.Write(data)
|
||||
str.WriteString("\n{{- end}}")
|
||||
name = strings.TrimSuffix(name, filepath.Ext(name))
|
||||
if name == "progress" {
|
||||
args.Progress = string(data)
|
||||
} else {
|
||||
str.WriteString("\n" + `{{define "`)
|
||||
str.WriteString(name)
|
||||
str.WriteString(`" -}}` + "\n")
|
||||
str.Write(data)
|
||||
str.WriteString("\n{{- end}}")
|
||||
}
|
||||
}
|
||||
|
||||
out, err := os.Create("osa_generated.go")
|
||||
|
@ -49,7 +56,8 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = generator.Execute(out, str.String())
|
||||
args.Templates = str.String()
|
||||
err = generator.Execute(out, args)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -108,5 +116,6 @@ import (
|
|||
var scripts = template.Must(template.New("").Funcs(template.FuncMap{"json": func(v interface{}) (string, error) {
|
||||
b, err := json.Marshal(v)
|
||||
return string(b), err
|
||||
}}).Parse(` + "`{{.}}`" + `))
|
||||
`))
|
||||
}}).Parse(` + "`{{.Templates}}`" + `))
|
||||
|
||||
var progress =` + "`\n{{.Progress}}`\n"))
|
||||
|
|
|
@ -15,8 +15,7 @@ function run(args) {
|
|||
var s
|
||||
try {
|
||||
s = $.readline('')
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
if (e.errorNumber === -128) $.exit(1)
|
||||
break
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package zenutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Run is internal.
|
||||
|
@ -47,6 +51,123 @@ func Run(ctx context.Context, script string, data interface{}) ([]byte, error) {
|
|||
return cmd.Output()
|
||||
}
|
||||
|
||||
func RunProgress(ctx context.Context) (m *progressMonitor, err error) {
|
||||
t, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
os.RemoveAll(t)
|
||||
}
|
||||
}()
|
||||
|
||||
var cmd *exec.Cmd
|
||||
name := filepath.Join(t, "progress.app")
|
||||
|
||||
cmd = exec.Command("osacompile", "-l", "JavaScript", "-o", name)
|
||||
cmd.Stdin = strings.NewReader(progress)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plist := filepath.Join(name, "Contents/Info.plist")
|
||||
|
||||
cmd = exec.Command("defaults", "write", plist, "LSUIElement", "true")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd = exec.Command("defaults", "write", plist, "CFBundleName", "")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var executable string
|
||||
cmd = exec.Command("defaults", "read", plist, "CFBundleExecutable")
|
||||
if out, err := cmd.Output(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
out = bytes.TrimSuffix(out, []byte{'\n'})
|
||||
executable = filepath.Join(name, "Contents/MacOS", string(out))
|
||||
}
|
||||
|
||||
cmd = exec.Command(executable)
|
||||
pipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
m = &progressMonitor{
|
||||
done: make(chan struct{}),
|
||||
lines: make(chan string),
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
pipe.Close()
|
||||
err := cmd.Wait()
|
||||
if cerr := ctx.Err(); cerr != nil {
|
||||
err = cerr
|
||||
}
|
||||
m.err = err
|
||||
close(m.done)
|
||||
os.RemoveAll(t)
|
||||
}()
|
||||
for {
|
||||
var line string
|
||||
select {
|
||||
case s, ok := <-m.lines:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
line = s
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(40 * time.Millisecond):
|
||||
}
|
||||
if _, err := pipe.Write([]byte(line + "\n")); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
type progressMonitor struct {
|
||||
err error
|
||||
done chan struct{}
|
||||
lines chan string
|
||||
}
|
||||
|
||||
func (m *progressMonitor) send(line string) error {
|
||||
select {
|
||||
case m.lines <- line:
|
||||
return nil
|
||||
case <-m.done:
|
||||
return m.err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *progressMonitor) Close() error {
|
||||
close(m.lines)
|
||||
<-m.done
|
||||
return m.err
|
||||
}
|
||||
|
||||
func (m *progressMonitor) Message(msg string) error {
|
||||
return m.send("#" + msg)
|
||||
}
|
||||
|
||||
func (m *progressMonitor) Progress(progress int) error {
|
||||
return m.send(strconv.Itoa(progress))
|
||||
}
|
||||
|
||||
// File is internal.
|
||||
type File struct {
|
||||
Operation string
|
||||
|
|
7
progress.go
Normal file
7
progress.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package zenity
|
||||
|
||||
type ProgressMonitor interface {
|
||||
Message(string) error
|
||||
Progress(int) error
|
||||
Close() error
|
||||
}
|
Loading…
Reference in a new issue