grim/hgkeeper

Use Go 1.22 and update dependencies
default tip
2 months ago, aklitzing
f33f223bc8fe
Use Go 1.22 and update dependencies

Reviewed at https://reviews.imfreedom.org/r/2949/
package hg
import (
"errors"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"go.uber.org/zap"
)
var (
hgExe string
)
type Command struct {
cmd *exec.Cmd
tmpHgrc string
writeable bool
}
func SetExe(path string) error {
path, err := exec.LookPath(path)
if err != nil {
if !errors.Is(err, exec.ErrDot) {
return err
}
}
hgExe = path
return nil
}
func (c *Command) Setup(repoName, username string) error {
hgrc, err := createHgrc(c.writeable)
if err != nil {
return err
}
c.tmpHgrc = hgrc
rcs := []string{}
// add the hgrc that controls writability
rcs = append(rcs, c.tmpHgrc)
// add the repo specific hgrc's
rcs = append(rcs, findHgrcsForRepo(repoName)...)
c.cmd.Env = append(
os.Environ(),
"HGRCPATH="+strings.Join(rcs, string(filepath.ListSeparator)),
"HGK_REPOSITORY="+repoName,
"HGK_USERNAME="+username,
)
return nil
}
func (c *Command) Teardown() {
if c.tmpHgrc != "" {
if err := os.Remove(c.tmpHgrc); err != nil {
zap.S().Warnf("failed to remove %q: %v", c.tmpHgrc, err)
}
c.tmpHgrc = ""
}
}
func (c *Command) Exec(repoName, username string) (string, error) {
c.Setup(repoName, username)
defer c.Teardown()
raw, err := c.Cmd().CombinedOutput()
return string(raw), err
}
func (c *Command) ExecPiped(repoName, username string, stdin io.Reader, stdout, stderr io.Writer) error {
if err := c.Setup(repoName, username); err != nil {
return err
}
defer c.Teardown()
cmd := c.Cmd()
pstdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
pstderr, err := cmd.StderrPipe()
if err != nil {
return err
}
pstdin, err := cmd.StdinPipe()
if err != nil {
return err
}
wg := &sync.WaitGroup{}
// we wait for stderr and stdout to finish
wg.Add(2)
if err := cmd.Start(); err != nil {
return err
}
go func() {
defer pstdin.Close()
if _, err := io.Copy(pstdin, stdin); err != nil {
zap.S().Errorf("Failed to read stdin: %v", err)
}
}()
go func() {
defer wg.Done()
if _, err := io.Copy(stdout, pstdout); err != nil {
zap.S().Errorf("Failed to write stdout: %v", err)
}
}()
go func() {
defer wg.Done()
if _, err := io.Copy(stderr, pstderr); err != nil {
zap.S().Errorf("Failed to write stderr: %v", err)
}
}()
// wait until all output is processed
wg.Wait()
return cmd.Wait()
}
func (c *Command) Cmd() *exec.Cmd {
return c.cmd
}
func Init(path string) *Command {
return &Command{
cmd: exec.Command(hgExe, "init", path),
}
}
func Serve(path string, writeable bool) *Command {
return &Command{
cmd: exec.Command(hgExe, "-R", path, "serve", "--stdio"),
writeable: writeable,
}
}
func Add(path string, files ...string) *Command {
args := append([]string{"add", "--cwd", path}, files...)
return &Command{
cmd: exec.Command(hgExe, args...),
}
}
func Commit(path, username, message string) *Command {
args := []string{
"commit",
"--cwd", path,
"--config", "ui.username=" + username,
"-m", message,
}
return &Command{
cmd: exec.Command(hgExe, args...),
}
}
func Config(setting string) *Command {
args := []string{
"config",
setting,
}
return &Command{
cmd: exec.Command(hgExe, args...),
}
}