- Created config.go with Config struct - Created daemon.go with Daemon struct and Start/Stop methods - Created logger.go for logging setup - Created process.go for lock/PID management - Created fingerprint.go for database validation - Created flock_unix.go/flock_windows.go for platform-specific locking - Created git.go for git operations Still TODO: - Implement runGlobalDaemon, startRPCServer, runSyncLoop - Create sync.go, rpc.go, jsonl.go, validation.go - Update cmd/bd/daemon.go to use daemonrunner Part of bd-5f26
93 lines
2.7 KiB
Go
93 lines
2.7 KiB
Go
package daemonrunner
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// isGitRepo checks if we're in a git repository
|
|
func isGitRepo() bool {
|
|
cmd := exec.Command("git", "rev-parse", "--git-dir")
|
|
return cmd.Run() == nil
|
|
}
|
|
|
|
// gitHasUpstream checks if the current branch has an upstream configured
|
|
func gitHasUpstream() bool {
|
|
cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}")
|
|
return cmd.Run() == nil
|
|
}
|
|
|
|
// gitHasChanges checks if the specified file has uncommitted changes
|
|
func gitHasChanges(ctx context.Context, filePath string) (bool, error) {
|
|
cmd := exec.CommandContext(ctx, "git", "status", "--porcelain", filePath)
|
|
output, err := cmd.Output()
|
|
if err != nil {
|
|
return false, fmt.Errorf("git status failed: %w", err)
|
|
}
|
|
return len(strings.TrimSpace(string(output))) > 0, nil
|
|
}
|
|
|
|
// gitCommit commits the specified file
|
|
func gitCommit(ctx context.Context, filePath string, message string) error {
|
|
// Stage the file
|
|
addCmd := exec.CommandContext(ctx, "git", "add", filePath)
|
|
if err := addCmd.Run(); err != nil {
|
|
return fmt.Errorf("git add failed: %w", err)
|
|
}
|
|
|
|
// Generate message if not provided
|
|
if message == "" {
|
|
message = fmt.Sprintf("bd sync: %s", time.Now().Format("2006-01-02 15:04:05"))
|
|
}
|
|
|
|
// Commit
|
|
commitCmd := exec.CommandContext(ctx, "git", "commit", "-m", message)
|
|
output, err := commitCmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("git commit failed: %w\n%s", err, output)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// gitPull pulls from the current branch's upstream
|
|
func gitPull(ctx context.Context) error {
|
|
// Get current branch name
|
|
branchCmd := exec.CommandContext(ctx, "git", "rev-parse", "--abbrev-ref", "HEAD")
|
|
branchOutput, err := branchCmd.Output()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get current branch: %w", err)
|
|
}
|
|
branch := strings.TrimSpace(string(branchOutput))
|
|
|
|
// Get remote name for current branch (usually "origin")
|
|
remoteCmd := exec.CommandContext(ctx, "git", "config", "--get", fmt.Sprintf("branch.%s.remote", branch))
|
|
remoteOutput, err := remoteCmd.Output()
|
|
if err != nil {
|
|
// If no remote configured, default to "origin"
|
|
remoteOutput = []byte("origin\n")
|
|
}
|
|
remote := strings.TrimSpace(string(remoteOutput))
|
|
|
|
// Pull with explicit remote and branch
|
|
cmd := exec.CommandContext(ctx, "git", "pull", remote, branch)
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("git pull failed: %w\n%s", err, output)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// gitPush pushes to the current branch's upstream
|
|
func gitPush(ctx context.Context) error {
|
|
cmd := exec.CommandContext(ctx, "git", "push")
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("git push failed: %w\n%s", err, output)
|
|
}
|
|
return nil
|
|
}
|