feat(gitsync): synka wiki-repot mot remote över SSH
- ed25519-deploy-nyckel genereras av servern (config-volymen, 0600), GIT_SSH_COMMAND med egen known_hosts (accept-new) - inställningar: remote-URL, live-gren, read-only, auto-synk-intervall - bakgrundssynk: endast fast-forward, flaggar attention vid merge-behov - pull/push, skapa/byt gren, merge-popup (ours/theirs per fil eller allt), abort, reset från remote med automatisk backup-gren - headless-konfig via config.json eller updateGitSync-mutationen - openssh-client tillagd i runtime-imagen; mutex kring alla git-operationer Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,11 +8,19 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Repo wraps a bare directory that is a Git repository.
|
||||
type Repo struct {
|
||||
root string
|
||||
// mu serialises whole operations (a background sync racing a user
|
||||
// save would otherwise corrupt index/merge state).
|
||||
mu sync.Mutex
|
||||
// sshCommand is exported to git as GIT_SSH_COMMAND when set, so
|
||||
// remotes can be reached with a dedicated key and known_hosts file
|
||||
// even though the server runs without a home directory.
|
||||
sshCommand string
|
||||
}
|
||||
|
||||
// Open returns a Repo for an existing directory, initialising Git if needed.
|
||||
@@ -35,6 +43,8 @@ func (r *Repo) initIfNeeded() error {
|
||||
|
||||
// Commit writes data to path and creates a Git commit authored by author.
|
||||
func (r *Repo) Commit(path, content, message, author, email string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
full := filepath.Join(r.root, path)
|
||||
if err := writeFile(full, content); err != nil {
|
||||
return err
|
||||
@@ -52,6 +62,8 @@ func (r *Repo) Commit(path, content, message, author, email string) error {
|
||||
|
||||
// Log returns the commit history for a file, including added/removed line counts.
|
||||
func (r *Repo) Log(path string) ([]LogEntry, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
out, err := r.run("log", "--format=COMMIT|%H|%an|%ae|%ai|%s", "--numstat", "--", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -92,24 +104,32 @@ func (r *Repo) Log(path string) ([]LogEntry, error) {
|
||||
|
||||
// Diff returns the unified diff between two commits for a file.
|
||||
func (r *Repo) Diff(path, fromHash, toHash string) (string, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
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) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
return r.run("show", fmt.Sprintf("%s:%s", hash, path))
|
||||
}
|
||||
|
||||
// HasUncommitted returns true if the working tree contains untracked or
|
||||
// modified files that have not yet been committed.
|
||||
func (r *Repo) HasUncommitted() bool {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
out, err := r.run("status", "--porcelain")
|
||||
return err == nil && strings.TrimSpace(out) != ""
|
||||
}
|
||||
|
||||
// CommitAll stages every file in the repo root and creates a commit.
|
||||
func (r *Repo) CommitAll(message, author, email string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if _, err := r.run("add", "-A"); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -123,6 +143,8 @@ func (r *Repo) CommitAll(message, author, email string) error {
|
||||
|
||||
// Move renames a file from oldPath to newPath and creates a Git commit.
|
||||
func (r *Repo) Move(oldPath, newPath, message, author, email string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if _, err := r.run("mv", oldPath, newPath); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -153,6 +175,10 @@ func writeFile(path, content string) error {
|
||||
|
||||
func (r *Repo) run(args ...string) (string, error) {
|
||||
cmd := exec.Command("git", append([]string{"-C", r.root}, args...)...)
|
||||
cmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
|
||||
if r.sshCommand != "" {
|
||||
cmd.Env = append(cmd.Env, "GIT_SSH_COMMAND="+r.sshCommand)
|
||||
}
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
Reference in New Issue
Block a user