aboutsummaryrefslogtreecommitdiffstats
path: root/cmd_linux.go
diff options
context:
space:
mode:
authorBernhard Guillon <Bernhard.Guillon@begu.org>2026-07-07 11:49:16 +0200
committerBernhard Guillon <Bernhard.Guillon@begu.org>2026-07-07 11:49:16 +0200
commit540d7476fb2a3ec812720158f797a3a916eadeba (patch)
treec246f315ff39391a25a8201a5847d7fa349ab543 /cmd_linux.go
parentc7fc7f7cdfc533b492b13b9a57689441878d1fee (diff)
downloadsourcewatch-540d7476fb2a3ec812720158f797a3a916eadeba.tar.gz
sourcewatch-540d7476fb2a3ec812720158f797a3a916eadeba.zip
Switch from Unix sockets to TCP for Docker Desktop compatibility
Architecture: - Container acts as TCP server (listens on :5151) - Windows binary connects as TCP client - Same protocol: newline-delimited JSON Usage: docker run -p 5151:5151 -v C:\src:/host:ro -v data:/data sourcewatch sourcewatch.exe -dir C:\src -connect localhost:5151 This avoids Docker Desktop's inability to mount Windows Unix sockets into Linux containers (they become directories instead of files).
Diffstat (limited to 'cmd_linux.go')
-rw-r--r--cmd_linux.go55
1 files changed, 29 insertions, 26 deletions
diff --git a/cmd_linux.go b/cmd_linux.go
index 65e8644..069881a 100644
--- a/cmd_linux.go
+++ b/cmd_linux.go
@@ -15,10 +15,10 @@ import (
)
var (
- hostDir = flag.String("host", "/host", "Host source directory (read-only)")
- dataDir = flag.String("data", "/data", "Data destination directory")
- dryRun = flag.Bool("dry-run", false, "Preview what would be synced without copying")
- socketPath = flag.String("socket", "/run/sourcewatch.sock", "Unix socket to receive events from (Windows watcher)")
+ hostDir = flag.String("host", "/host", "Host source directory (read-only)")
+ dataDir = flag.String("data", "/data", "Data destination directory")
+ dryRun = flag.Bool("dry-run", false, "Preview what would be synced without copying")
+ listen = flag.String("listen", ":5151", "TCP address to listen on for Windows watcher connections")
)
func run() {
@@ -40,8 +40,8 @@ func run() {
stack := NewGitignoreStack(*hostDir)
- if *socketPath == "" {
- logInfo("no -socket specified, running standalone (full scan)")
+ if *listen == "" {
+ logInfo("no -listen specified, running standalone (full scan)")
manifest, err := initialSync(*hostDir, *dataDir, stack, *dryRun)
if err != nil {
logErrorf("initial sync failed: %v", err)
@@ -57,29 +57,35 @@ func run() {
return
}
- logInfo("watcher: connecting to %s ...", *socketPath)
+ ln, err := net.Listen("tcp", *listen)
+ if err != nil {
+ logErrorf("listen: %v", err)
+ os.Exit(1)
+ }
+ defer ln.Close()
+
+ logInfo("watcher: listening on %s", *listen)
+ logInfo("watcher: waiting for Windows watcher to connect ...")
- var conn net.Conn
for {
if ctx.Err() != nil {
- logErrorf("cancelled while connecting")
- os.Exit(1)
- }
- conn, err = net.Dial("unix", *socketPath)
- if err == nil {
- break
+ return
}
- logDebug("connect failed: %v, retrying...", err)
- select {
- case <-ctx.Done():
- logErrorf("cancelled while connecting")
- os.Exit(1)
- case <-time.After(1 * time.Second):
+
+ conn, err := ln.Accept()
+ if err != nil {
+ logErrorf("accept: %v", err)
+ continue
}
+
+ logInfo("watcher: client connected from %s", conn.RemoteAddr())
+ handleClient(conn, stack)
+ logInfo("watcher: client disconnected, waiting for reconnect ...")
}
- defer conn.Close()
+}
- logInfo("watcher: connected, receiving manifest ...")
+func handleClient(conn net.Conn, stack *GitignoreStack) {
+ defer conn.Close()
scanner := bufio.NewScanner(conn)
remoteManifest := &Manifest{Files: make(map[string]FileMeta)}
@@ -134,7 +140,7 @@ func run() {
}
if err := scanner.Err(); err != nil {
- logErrorf("socket read: %v", err)
+ logErrorf("read: %v", err)
}
}
@@ -142,7 +148,6 @@ func syncFromManifest(remote *Manifest, stack *GitignoreStack) {
stats := &syncStats{}
start := time.Now()
- // Scan local /data to get current state (fast, local volume)
localManifest := scanLocalDirectory(*dataDir)
for relPath, remoteMeta := range remote.Files {
@@ -157,7 +162,6 @@ func syncFromManifest(remote *Manifest, stack *GitignoreStack) {
destPath := filepath.Join(*dataDir, relPath)
srcPath := filepath.Join(*hostDir, relPath)
- // Check if file already exists locally with same metadata
if localMeta, exists := localManifest.Files[relPath]; exists {
if localMeta.Size == remoteMeta.Size &&
localMeta.Mode == remoteMeta.Mode &&
@@ -167,7 +171,6 @@ func syncFromManifest(remote *Manifest, stack *GitignoreStack) {
}
}
- // Need to sync
info, err := os.Lstat(srcPath)
if err != nil {
if os.IsNotExist(err) {