Compare commits
2 Commits
4257a9b615
...
a178536472
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a178536472 | ||
|
|
3bece46638 |
1
master/.gitignore
vendored
Normal file
1
master/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
master
|
||||
84
master/devrunner.go
Normal file
84
master/devrunner.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// a vibe coded el cheapo: https://claude.ai/chat/328ca558-1019-49b9-9f08-e85cfcea2ceb
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func runProcess(ctx context.Context, wg *sync.WaitGroup, name, command string) {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Printf("[%s] Stopping\n", name)
|
||||
return
|
||||
default:
|
||||
fmt.Printf("[%s] Starting: %s\n", name, command)
|
||||
|
||||
// Create command with context for cancellation
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", command)
|
||||
|
||||
// Setup stdout pipe
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[%s] Error creating stdout pipe: %v\n", name, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Setup stderr pipe
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[%s] Error creating stderr pipe: %v\n", name, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Start the command
|
||||
if err := cmd.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[%s] Error starting command: %v\n", name, err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// Copy output in separate goroutines
|
||||
var ioWg sync.WaitGroup
|
||||
ioWg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer ioWg.Done()
|
||||
io.Copy(os.Stdout, stdout)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer ioWg.Done()
|
||||
io.Copy(os.Stderr, stderr)
|
||||
}()
|
||||
|
||||
// Wait for command to finish
|
||||
err = cmd.Wait()
|
||||
ioWg.Wait() // Ensure all output is copied
|
||||
|
||||
// Check if we should restart
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Printf("[%s] Stopped\n", name)
|
||||
return
|
||||
default:
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[%s] Process exited with error: %v\n", name, err)
|
||||
} else {
|
||||
fmt.Printf("[%s] Process exited normally\n", name)
|
||||
}
|
||||
fmt.Printf("[%s] Restarting in 1 second...\n", name)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
master/filechange.go
Normal file
6
master/filechange.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
type FileChange struct {
|
||||
Path string
|
||||
Operation string
|
||||
}
|
||||
8
master/go.mod
Normal file
8
master/go.mod
Normal file
@@ -0,0 +1,8 @@
|
||||
module philologue.net/diachron/master
|
||||
|
||||
go 1.23.3
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
)
|
||||
4
master/go.sum
Normal file
4
master/go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
50
master/main.go
Normal file
50
master/main.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
// "context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
// "sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// var program1 = os.Getenv("BUILD_COMMAND")
|
||||
//var program2 = os.Getenv("RUN_COMMAND")
|
||||
|
||||
var watchedDir = os.Getenv("WATCHED_DIR")
|
||||
|
||||
// Create context for graceful shutdown
|
||||
// ctx, cancel := context.WithCancel(context.Background())
|
||||
//defer cancel()
|
||||
|
||||
// Setup signal handling
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
fileChanges := make(chan FileChange, 10)
|
||||
|
||||
go watchFiles(watchedDir, fileChanges)
|
||||
|
||||
go printChanges(fileChanges)
|
||||
|
||||
// WaitGroup to track both processes
|
||||
// var wg sync.WaitGroup
|
||||
|
||||
// Start both processes
|
||||
//wg.Add(2)
|
||||
// go runProcess(ctx, &wg, "builder", program1)
|
||||
// go runProcess(ctx, &wg, "runner", program2)
|
||||
|
||||
// Wait for interrupt signal
|
||||
<-sigCh
|
||||
fmt.Println("\nReceived interrupt signal, shutting down...")
|
||||
|
||||
// Cancel context to signal goroutines to stop
|
||||
/// cancel()
|
||||
|
||||
// Wait for both processes to finish
|
||||
// wg.Wait()
|
||||
fmt.Println("All processes terminated cleanly")
|
||||
}
|
||||
11
master/printchanges.go
Normal file
11
master/printchanges.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func printChanges(changes <-chan FileChange) {
|
||||
for change := range changes {
|
||||
fmt.Printf("[%s] %s\n", change.Operation, change.Path)
|
||||
}
|
||||
}
|
||||
74
master/watchfiles.go
Normal file
74
master/watchfiles.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func watchFiles(dir string, changes chan<- FileChange) {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// Add all directories recursively
|
||||
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
err = watcher.Add(path)
|
||||
if err != nil {
|
||||
log.Printf("Error watching %s: %v\n", path, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle different types of events
|
||||
var operation string
|
||||
switch {
|
||||
case event.Op&fsnotify.Write == fsnotify.Write:
|
||||
operation = "MODIFIED"
|
||||
case event.Op&fsnotify.Create == fsnotify.Create:
|
||||
operation = "CREATED"
|
||||
// If a new directory is created, start watching it
|
||||
if info, err := os.Stat(event.Name); err == nil && info.IsDir() {
|
||||
watcher.Add(event.Name)
|
||||
}
|
||||
case event.Op&fsnotify.Remove == fsnotify.Remove:
|
||||
operation = "REMOVED"
|
||||
case event.Op&fsnotify.Rename == fsnotify.Rename:
|
||||
operation = "RENAMED"
|
||||
case event.Op&fsnotify.Chmod == fsnotify.Chmod:
|
||||
operation = "CHMOD"
|
||||
default:
|
||||
operation = "UNKNOWN"
|
||||
}
|
||||
|
||||
changes <- FileChange{
|
||||
Path: event.Name,
|
||||
Operation: operation,
|
||||
}
|
||||
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Printf("Watcher error: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user