Skip to content
go-libfossil Artifact [84bb62252b]
Login

Artifact [84bb62252b]

Artifact 84bb62252b905e6ffd0191ef218f2cd7d8300ff1723e8c9d42146b5c7cfdc798:


package libfossil_test

import (
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	libfossil "github.com/danmestas/go-libfossil"
)

// A sparse checkout stays a checkout fossil can open safely
// (draft-fossil-sparse-cone-00 ยง3.1): the cone lives in a vvar fossil
// ignores, and vfile keeps a row for every file. fossil therefore sees the
// uncovered files as MISSING and refuses to commit -- it cannot commit them
// away -- and its revert brings them back, after which go-libfossil still
// works within the cone and ignores the restored files.
func TestSparseCheckoutUnderFossil(t *testing.T) {
	bin, repoPath, _ := newFossilCheckout(t)
	r, err := libfossil.Open(repoPath)
	if err != nil {
		t.Fatal(err)
	}
	defer r.Close()
	tip, _, err := r.Commit(libfossil.CommitOpts{Comment: "tree", User: "u", Files: []libfossil.FileToCommit{
		{Name: "a.txt", Content: []byte("one\n")}, {Name: "b.txt", Content: []byte("two\n")},
		{Name: "src/s.txt", Content: []byte("src\n")}, {Name: "tools/t.txt", Content: []byte("tools\n")},
	}})
	if err != nil {
		t.Fatal(err)
	}
	cone, err := libfossil.NewCone([]string{"src"}, nil)
	if err != nil {
		t.Fatal(err)
	}
	dir := filepath.Join(t.TempDir(), "sparse")
	co, err := r.CreateCheckout(dir, libfossil.CheckoutCreateOpts{Cone: cone})
	if err != nil {
		t.Fatal(err)
	}
	if err := co.Extract(tip, libfossil.ExtractOpts{Force: true}); err != nil {
		t.Fatal(err)
	}
	co.Close()
	writeFile(t, filepath.Join(dir, "src/s.txt"), "edited by fossil\n")
	leaves := strings.TrimSpace(fossilRun(t, bin, dir, "leaves"))

	status := fossilRun(t, bin, dir, "status")
	for _, want := range []string{"MISSING    a.txt", "MISSING    tools/t.txt", "EDITED     src/s.txt"} {
		if !strings.Contains(status, want) {
			t.Fatalf("fossil status does not show %q:\n%s", want, status)
		}
	}
	cmd := exec.Command(bin, "commit", "-m", "from fossil", "--no-warnings")
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err == nil {
		t.Fatalf("fossil committed a sparse checkout:\n%s", out)
	}
	if !strings.Contains(strings.ToLower(string(out)), "no such file") {
		t.Fatalf("fossil refused the commit, but not for the missing files:\n%s", out)
	}
	if got := strings.TrimSpace(fossilRun(t, bin, dir, "leaves")); got != leaves {
		t.Fatalf("a refused fossil commit changed the leaves:\n%s\nthen\n%s", leaves, got)
	}

	// fossil's revert densifies the tree; go-libfossil keeps to its cone.
	fossilRun(t, bin, dir, "revert", "a.txt", "b.txt", "tools/t.txt")
	if _, err := os.Stat(filepath.Join(dir, "tools/t.txt")); err != nil {
		t.Fatalf("fossil revert did not restore an uncovered file: %v", err)
	}
	co, err = r.OpenCheckout(dir, libfossil.CheckoutOpenOpts{})
	if err != nil {
		t.Fatal(err)
	}
	defer co.Close()
	changes, err := co.Status()
	if err != nil {
		t.Fatal(err)
	}
	if len(changes) != 1 || changes[0].Name != "src/s.txt" || changes[0].Change != "modified" {
		t.Fatalf("go-libfossil status after fossil: %+v", changes)
	}
	rid, _, err := co.Checkin(libfossil.CheckoutCommitOpts{Message: "sparse", User: "u"})
	if err != nil {
		t.Fatal(err)
	}
	files, err := r.ListFiles(rid)
	if err != nil {
		t.Fatal(err)
	}
	if len(files) != 4 {
		t.Fatalf("the sparse commit lists %d files, want 4", len(files))
	}
}