grim/hgkeeper

ebc5f568d629
Add a note about downloads and pgp verification to the readme
package hg
import (
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
log "github.com/sirupsen/logrus"
"keep.imfreedom.org/grim/hgkeeper/access"
)
type Command struct {
cmd *exec.Cmd
tmpHgrc string
writeable bool
}
func (c *Command) Setup(repoName, username string) error {
hgrc, err := createHgrc(c.writeable)
if err != nil {
return err
}
c.tmpHgrc = hgrc
// site.hgrc is deprecated, but we still support it for now
rcs := []string{filepath.Join(access.AdminRepoPath(), "site.hgrc")}
// add the repo specific hgrc's
rcs = append(rcs, findHgrcsForRepo(repoName)...)
// add the hgrc that controls writability
rcs = append(rcs, c.tmpHgrc)
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 {
log.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 {
log.Errorf("Failed to read stdin: %v", err)
}
}()
go func() {
defer wg.Done()
if _, err := io.Copy(stdout, pstdout); err != nil {
log.Errorf("Failed to write stdout: %v", err)
}
}()
go func() {
defer wg.Done()
if _, err := io.Copy(stderr, pstderr); err != nil {
log.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("hg", "init", path),
}
}
func Serve(path string, writeable bool) *Command {
return &Command{
cmd: exec.Command("hg", "-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("hg", args...),
}
}
func Commit(path, username, message string) *Command {
args := []string{
"commit",
"--cwd", path,
"--config", "ui.username=" + username,
"-m", message,
}
return &Command{
cmd: exec.Command("hg", args...),
}
}
func Config(setting string) *Command {
args := []string{
"config",
setting,
}
return &Command{
cmd: exec.Command("hg", args...),
}
}