128 lines
3.1 KiB
Go
128 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
|
|
"git.dws.rip/DWS/onyx/internal/core"
|
|
"git.dws.rip/DWS/onyx/internal/daemon"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
version = "0.1.0"
|
|
repoPath string
|
|
interval time.Duration
|
|
debounce time.Duration
|
|
pidFile string
|
|
)
|
|
|
|
func main() {
|
|
rootCmd := &cobra.Command{
|
|
Use: "onxd",
|
|
Short: "Onyx Daemon - Transparent versioning daemon",
|
|
Long: `The Onyx daemon monitors your repository for changes and automatically
|
|
creates snapshots of your work. This enables transparent versioning without
|
|
manual commits.`,
|
|
Version: version,
|
|
RunE: runDaemon,
|
|
}
|
|
|
|
// Add flags
|
|
rootCmd.PersistentFlags().StringVarP(&repoPath, "repo", "r", ".", "Path to the Onyx repository")
|
|
rootCmd.PersistentFlags().DurationVarP(&interval, "interval", "i", 1*time.Second, "Ticker interval for periodic checks")
|
|
rootCmd.PersistentFlags().DurationVarP(&debounce, "debounce", "d", 500*time.Millisecond, "Debounce duration for filesystem events")
|
|
|
|
if err := rootCmd.Execute(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func runDaemon(cmd *cobra.Command, args []string) error {
|
|
// Resolve repository path
|
|
absPath, err := filepath.Abs(repoPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to resolve repository path: %w", err)
|
|
}
|
|
|
|
// Check if this is an Onyx repository
|
|
if !core.IsOnyxRepo(absPath) {
|
|
return fmt.Errorf("not an Onyx repository: %s", absPath)
|
|
}
|
|
|
|
// Open the repository
|
|
repo, err := core.Open(absPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open repository: %w", err)
|
|
}
|
|
defer repo.Close()
|
|
|
|
// Create daemon configuration
|
|
config := &daemon.Config{
|
|
Debounce: debounce,
|
|
TickerInterval: interval,
|
|
RepoPath: absPath,
|
|
}
|
|
|
|
// Create the daemon
|
|
d, err := daemon.New(repo, config)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create daemon: %w", err)
|
|
}
|
|
|
|
// Write PID file
|
|
pidFile = filepath.Join(repo.GetOnyxPath(), "daemon.pid")
|
|
if err := writePIDFile(pidFile); err != nil {
|
|
return fmt.Errorf("failed to write PID file: %w", err)
|
|
}
|
|
defer os.Remove(pidFile)
|
|
|
|
// Set up signal handlers
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
// Start the daemon
|
|
if err := d.Start(); err != nil {
|
|
return fmt.Errorf("failed to start daemon: %w", err)
|
|
}
|
|
|
|
log.Printf("Onyx daemon started (PID: %d)", os.Getpid())
|
|
log.Printf("Watching repository: %s", absPath)
|
|
log.Printf("Debounce: %v, Interval: %v", debounce, interval)
|
|
|
|
// Wait for shutdown signal
|
|
sig := <-sigChan
|
|
log.Printf("Received signal: %v", sig)
|
|
|
|
// Stop the daemon
|
|
if err := d.Stop(); err != nil {
|
|
return fmt.Errorf("failed to stop daemon: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// writePIDFile writes the current process ID to a file
|
|
func writePIDFile(path string) error {
|
|
pid := os.Getpid()
|
|
return os.WriteFile(path, []byte(fmt.Sprintf("%d\n", pid)), 0644)
|
|
}
|
|
|
|
// readPIDFile reads the process ID from a file
|
|
func readPIDFile(path string) (int, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var pid int
|
|
_, err = fmt.Sscanf(string(data), "%d", &pid)
|
|
return pid, err
|
|
}
|