Files
Archivum/backend/internal/git/git.go
brasse b e6b64e3344 feat: Archivum skeleton — Go/GraphQL backend + Vue 3 PWA frontend
Full project scaffold: multi-stage Dockerfile (ARM64/AMD64), AsciiDoc↔TipTap
bridge, Setup Wizard, CodeMirror source editor, Git-backed storage layer,
LDAP+JWT auth skeleton, Tailwind mobile-first layout, and VS Code build/push
tasks targeting registry at 192.168.0.19:5000.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 13:07:01 +02:00

105 lines
2.4 KiB
Go

package git
import (
"bytes"
"fmt"
"os/exec"
"path/filepath"
"strings"
)
// Repo wraps a bare directory that is a Git repository.
type Repo struct {
root string
}
// Open returns a Repo for an existing directory, initialising Git if needed.
func Open(root string) (*Repo, error) {
r := &Repo{root: root}
if err := r.initIfNeeded(); err != nil {
return nil, err
}
return r, nil
}
func (r *Repo) initIfNeeded() error {
out, _ := r.run("rev-parse", "--is-inside-work-tree")
if strings.TrimSpace(out) == "true" {
return nil
}
_, err := r.run("init")
return err
}
// Commit writes data to path and creates a Git commit authored by author.
func (r *Repo) Commit(path, content, message, author, email string) error {
full := filepath.Join(r.root, path)
if err := writeFile(full, content); err != nil {
return err
}
if _, err := r.run("add", path); err != nil {
return err
}
_, err := r.run(
"-c", fmt.Sprintf("user.name=%s", author),
"-c", fmt.Sprintf("user.email=%s", email),
"commit", "-m", message,
)
return err
}
// Log returns the commit history for a file.
func (r *Repo) Log(path string) ([]LogEntry, error) {
out, err := r.run("log", "--format=%H|%an|%ae|%ai|%s", "--", path)
if err != nil {
return nil, err
}
var entries []LogEntry
for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
if line == "" {
continue
}
parts := strings.SplitN(line, "|", 5)
if len(parts) == 5 {
entries = append(entries, LogEntry{
Hash: parts[0],
Author: parts[1],
Email: parts[2],
Date: parts[3],
Subject: parts[4],
})
}
}
return entries, nil
}
// Diff returns the unified diff between two commits for a file.
func (r *Repo) Diff(path, fromHash, toHash string) (string, error) {
out, err := r.run("diff", fromHash, toHash, "--", path)
return out, err
}
// Show returns the file content at a specific commit.
func (r *Repo) Show(hash, path string) (string, error) {
return r.run("show", fmt.Sprintf("%s:%s", hash, path))
}
type LogEntry struct {
Hash string
Author string
Email string
Date string
Subject string
}
func (r *Repo) run(args ...string) (string, error) {
cmd := exec.Command("git", append([]string{"-C", r.root}, args...)...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("git %v: %w — %s", args, err, stderr.String())
}
return stdout.String(), nil
}