Reticulum-Go/pkg/rnsgit/progress.go

92 lines
2 KiB
Go

// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2024-2026 Quad4.io
package rnsgit
import (
"encoding/json"
"fmt"
"io"
"maps"
"os"
"os/exec"
"strings"
)
func (c *Client) emitProgress(event string, fields map[string]any) {
if !c.jsonProgress || c.progressWriter == nil {
return
}
m := map[string]any{"event": event}
maps.Copy(m, fields)
b, err := json.Marshal(m)
if err != nil {
return
}
fmt.Fprintln(c.progressWriter, string(b))
}
func statusLine(w io.Writer, msg string) {
if w == nil {
return
}
fmt.Fprint(w, msg)
}
func statusLinef(w io.Writer, format string, args ...any) {
if w == nil {
return
}
fmt.Fprintf(w, format, args...)
}
func resolveEditor() (string, error) {
if ed := strings.TrimSpace(os.Getenv("EDITOR")); ed != "" {
name := strings.Fields(ed)[0]
path, err := exec.LookPath(name)
if err != nil {
return "", fmt.Errorf("EDITOR %q not executable: %w", name, err)
}
return path, nil
}
for _, fb := range []string{"nano", "vim", "vi"} {
if path, err := exec.LookPath(fb); err == nil {
return path, nil
}
}
return "", fmt.Errorf("no editor found, set EDITOR or use -content")
}
func editWithEditor(initial string) (string, bool, error) {
editor, err := resolveEditor()
if err != nil {
return "", false, err
}
tmp, err := os.CreateTemp("", "rnsgit-edit-*")
if err != nil {
return "", false, err
}
path := tmp.Name()
defer os.Remove(path)
if _, err := tmp.WriteString(initial); err != nil {
if closeErr := tmp.Close(); closeErr != nil {
return "", false, fmt.Errorf("write temp file: %w (close: %v)", err, closeErr)
}
return "", false, err
}
if err := tmp.Close(); err != nil {
return "", false, err
}
cmd := exec.Command(editor, path) // #nosec G204 -- editor from exec.LookPath, path from os.CreateTemp
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return "", false, err
}
out, err := os.ReadFile(path) // #nosec G304 -- temp editor file
if err != nil {
return "", false, err
}
return string(out), true, nil
}