Skip to content
quarry Artifact [2d3aa1bd1d]
Login

Artifact [2d3aa1bd1d]

Artifact 2d3aa1bd1de951f0364d6ecb97823d7292f0c0fd23e56d5e61aff193384ff057:


package zitcli

import (
	"bytes"
	"context"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"craftdesign.group/quarry/internal/timing"
)

// Init creates an empty repository at dir, creating dir if needed.
//
// A package function rather than a Client method because a Client is
// bound to a repository that already exists; this is what makes one.
func Init(ctx context.Context, dir string) error {
	return create(ctx, "init", []string{"init", dir}, dir)
}

// Clone copies the repository served at url into dir.
//
// zit saves url as dir's default remote, and never with a password: a
// `user:secret@host` URL is stored as `user@host`. That is worth knowing
// here because quarry keeps its own mirror configuration — the saved
// remote is a convenience for anyone running zit by hand in that
// directory, not the thing quarry's scheduler reads.
func Clone(ctx context.Context, url, dir string) error {
	return create(ctx, "clone", []string{"clone", url, dir}, dir)
}

// create runs a repository-making verb. These are the two zit calls
// with no repository to name, so they take neither -R nor a working
// directory — the target is an argument.
func create(ctx context.Context, verb string, args []string, dir string) error {
	if ctx == nil {
		ctx = context.Background()
	}
	start := time.Now()
	cmd := exec.CommandContext(ctx, "zit", args...)
	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	_, err := cmd.Output()
	timing.Record(ctx, timing.Zit, time.Since(start))
	if err != nil {
		return fmt.Errorf("zitcli: %s %s: %w: %s", verb, dir, err,
			strings.TrimSpace(stderr.String()))
	}
	return nil
}