package zitcli
import (
"bytes"
"context"
"fmt"
"os"
"strings"
"craftdesign.group/quarry/internal/lease"
)
// GitExport exports the store's new check-ins into the Git repository at
// mirror and pushes trunk to remote's branch, fast-forward only (RFC
// 0022), with env added to the child's environment: the caller names
// the ssh command and its key there. It answers zit's output either
// way, because on a refused push that output is the only account of
// why.
//
// A write: zit records the mirror in the store's config. Unattended
// and ungated like the other writes, so a push is not abandoned because
// a listing was busy; ctx bounds it, and losing the lease ends it.
func (c *Client) GitExport(tok lease.Token, ctx context.Context, mirror, remote, branch string, env []string) (string, error) {
if err := tok.Err(); err != nil {
return "", err
}
ctx, stop := underLease(ctx, tok)
defer stop()
args := []string{"git", "export", mirror, "--autopush", remote, "--push-branch", branch, "--quiet", "-R", c.repo}
if err := checkArgs(args); err != nil {
return "", err
}
cmd, done := spawnUnattended(ctx, repoName(c.repo), "git-mirror", args...)
defer done()
if cmd.Err != nil {
return "", cmd.Err
}
cmd.Env = append(os.Environ(), env...)
// Bounded as a whole: cancelling (the deadline, a lost lease, a
// stop) kills git and ssh with zit, and the pipes are closed for
// them if anything still holds them.
ownGroup(cmd)
cmd.WaitDelay = waitDelay
var out bytes.Buffer
cmd.Stdout, cmd.Stderr = &out, &out
if err := cmd.Run(); err != nil {
return strings.TrimSpace(out.String()), fmt.Errorf("zit git export: %w", err)
}
return strings.TrimSpace(out.String()), nil
}