diff --git a/cli/htmgo/debounce.go b/cli/htmgo/internal/debounce.go similarity index 97% rename from cli/htmgo/debounce.go rename to cli/htmgo/internal/debounce.go index 67c4759..6a149a4 100644 --- a/cli/htmgo/debounce.go +++ b/cli/htmgo/internal/debounce.go @@ -1,4 +1,4 @@ -package main +package internal import ( "sync" diff --git a/cli/htmgo/logger.go b/cli/htmgo/internal/logger.go similarity index 89% rename from cli/htmgo/logger.go rename to cli/htmgo/internal/logger.go index 053adc8..12bb860 100644 --- a/cli/htmgo/logger.go +++ b/cli/htmgo/internal/logger.go @@ -1,4 +1,4 @@ -package main +package internal import ( "log/slog" @@ -6,7 +6,7 @@ import ( "strings" ) -func getLogLevel() slog.Level { +func GetLogLevel() slog.Level { // Get the log level from the environment variable logLevel := os.Getenv("LOG_LEVEL") switch strings.ToUpper(logLevel) { diff --git a/cli/htmgo/runner.go b/cli/htmgo/runner.go index 8bb4f07..ab27c44 100644 --- a/cli/htmgo/runner.go +++ b/cli/htmgo/runner.go @@ -4,6 +4,7 @@ import ( "bufio" "flag" "fmt" + "github.com/maddalax/htmgo/cli/htmgo/internal" "github.com/maddalax/htmgo/cli/htmgo/tasks/astgen" "github.com/maddalax/htmgo/cli/htmgo/tasks/copyassets" "github.com/maddalax/htmgo/cli/htmgo/tasks/css" @@ -48,7 +49,7 @@ func main() { return } - slog.SetLogLoggerLevel(getLogLevel()) + slog.SetLogLoggerLevel(internal.GetLogLevel()) taskName := os.Args[1] @@ -63,7 +64,7 @@ func main() { copyassets.CopyAssets() - fmt.Printf("Generating CSS...this may take a few seconds.\n") + fmt.Printf("Generating CSS...\n") css.GenerateCss(process.ExitOnError) wg := sync.WaitGroup{} @@ -82,11 +83,8 @@ func main() { wg.Wait() - go func() { - css.GenerateCssWatch(process.ExitOnError) - }() - fmt.Printf("Starting server...\n") + process.KillAll() go func() { _ = run.Server() }() diff --git a/cli/htmgo/signals.go b/cli/htmgo/signals.go index e7c4497..4347ec2 100644 --- a/cli/htmgo/signals.go +++ b/cli/htmgo/signals.go @@ -23,7 +23,8 @@ func RegisterSignals() chan bool { fmt.Println("Received signal:", sig) // Perform cleanup fmt.Println("Cleaning up...") - process.KillAll() + + process.OnShutdown() // Signal that cleanup is done done <- true }() diff --git a/cli/htmgo/tasks/astgen/writer.go b/cli/htmgo/tasks/astgen/writer.go index 578f3eb..2d6e876 100644 --- a/cli/htmgo/tasks/astgen/writer.go +++ b/cli/htmgo/tasks/astgen/writer.go @@ -62,8 +62,12 @@ func WriteFile(path string, cb func(content *ast.File) string) { } } - // Define the file path where you want to save the buffer - process.Run("git add "+path, process.Silent) + cmd := "git add " + path + process.Run(process.NewRawCommand( + cmd, + cmd, + process.Silent, + )) // Save the buffer to a file err = os.WriteFile(path, bytes, 0644) diff --git a/cli/htmgo/tasks/copyassets/bundle.go b/cli/htmgo/tasks/copyassets/bundle.go index 45132d3..75fed1c 100644 --- a/cli/htmgo/tasks/copyassets/bundle.go +++ b/cli/htmgo/tasks/copyassets/bundle.go @@ -101,5 +101,6 @@ func CopyAssets() { log.Fatalf("Error: %v", err) } - process.Run(fmt.Sprintf("cd %s && git add .", destDirCss), process.Silent) + cmd := fmt.Sprintf("cd %s && git add .", destDirCss) + process.Run(process.NewRawCommand(cmd, cmd, process.Silent)) } diff --git a/cli/htmgo/tasks/css/css.go b/cli/htmgo/tasks/css/css.go index 49f1266..ba41f1c 100644 --- a/cli/htmgo/tasks/css/css.go +++ b/cli/htmgo/tasks/css/css.go @@ -42,19 +42,8 @@ func GenerateCss(flags ...process.RunFlag) error { return nil } exec := GetTailwindExecutableName() - return process.RunMany([]string{ - fmt.Sprintf("%s -i ./assets/css/input.css -o ./assets/dist/main.css -c ./tailwind.config.js", exec), - }, append(flags, process.Silent)...) -} - -func GenerateCssWatch(flags ...process.RunFlag) error { - if !Setup() { - return nil - } - exec := GetTailwindExecutableName() - return process.RunMany([]string{ - fmt.Sprintf("%s -i ./assets/css/input.css -o ./assets/dist/main.css -c ./tailwind.config.js --watch=always", exec), - }, append(flags, process.KillOnlyOnExit, process.Silent)...) + cmd := fmt.Sprintf("%s -i ./assets/css/input.css -o ./assets/dist/main.css -c ./tailwind.config.js", exec) + return process.Run(process.NewRawCommand("tailwind", cmd, append(flags, process.Silent)...)) } func downloadTailwindCli() { @@ -90,7 +79,9 @@ func downloadTailwindCli() { } fileName := fmt.Sprintf(`tailwindcss-%s`, distro) url := fmt.Sprintf(`https://github.com/tailwindlabs/tailwindcss/releases/latest/download/%s`, fileName) - process.Run(fmt.Sprintf(`curl -LO %s`, url), process.ExitOnError) + + cmd := fmt.Sprintf(`curl -LO %s`, url) + process.Run(process.NewRawCommand("tailwind-cli-download", cmd, process.ExitOnError)) outputFileName := GetTailwindExecutableName() newPath := filepath.Join(process.GetWorkingDir(), outputFileName) @@ -100,7 +91,9 @@ func downloadTailwindCli() { newPath) if os != "windows" { - err = process.Run(fmt.Sprintf(`chmod +x %s`, newPath), process.ExitOnError) + err = process.Run(process.NewRawCommand("chmod-tailwind-cli", + fmt.Sprintf(`chmod +x %s`, newPath), + process.ExitOnError)) } if err != nil { diff --git a/cli/htmgo/tasks/downloadtemplate/main.go b/cli/htmgo/tasks/downloadtemplate/main.go index 4ef6286..6546034 100644 --- a/cli/htmgo/tasks/downloadtemplate/main.go +++ b/cli/htmgo/tasks/downloadtemplate/main.go @@ -43,7 +43,7 @@ func DownloadTemplate(outPath string) { fmt.Printf("Downloading template %s\n to %s", templateName, tempOut) - err := process.Run("git clone https://github.com/maddalax/htmgo --depth=1 "+tempOut, process.ExitOnError) + err := process.Run(process.NewRawCommand("clone-template", "git clone https://github.com/maddalax/htmgo --depth=1 "+tempOut, process.ExitOnError)) if err != nil { log.Fatalf("Error cloning the template, error: %s\n", err.Error()) @@ -75,7 +75,7 @@ func DownloadTemplate(outPath string) { } for _, command := range commands { - process.Run(strings.Join(command, " "), process.ExitOnError) + process.Run(process.NewRawCommand("", strings.Join(command, " "), process.ExitOnError)) } _ = util.ReplaceTextInFile(filepath.Join(newDir, "go.mod"), diff --git a/cli/htmgo/tasks/process/pid_unix.go b/cli/htmgo/tasks/process/pid_unix.go index 95ad994..4ab99ae 100644 --- a/cli/htmgo/tasks/process/pid_unix.go +++ b/cli/htmgo/tasks/process/pid_unix.go @@ -4,16 +4,23 @@ package process import ( "errors" + "log/slog" "os" "os/exec" "syscall" + "time" ) -func KillProcess(process *os.Process) error { - if process == nil { +func KillProcess(process CmdWithFlags) error { + if process.Cmd == nil || process.Cmd.Process == nil { return nil } - return syscall.Kill(-process.Pid, syscall.SIGKILL) + slog.Debug("killing process", + slog.String("name", process.Name), + slog.Int("pid", process.Cmd.Process.Pid)) + _ = syscall.Kill(-process.Cmd.Process.Pid, syscall.SIGKILL) + time.Sleep(time.Millisecond * 50) + return nil } func PrepareCommand(command *exec.Cmd) { diff --git a/cli/htmgo/tasks/process/pid_windows.go b/cli/htmgo/tasks/process/pid_windows.go index 99acc88..7036a92 100644 --- a/cli/htmgo/tasks/process/pid_windows.go +++ b/cli/htmgo/tasks/process/pid_windows.go @@ -2,18 +2,17 @@ package process import ( "fmt" - "os" "os/exec" "strconv" "time" ) import "golang.org/x/sys/windows" -func KillProcess(process *os.Process) error { - if process == nil { +func KillProcess(process CmdWithFlags) error { + if process.Cmd == nil || process.Cmd.Process == nil { return nil } - Run(fmt.Sprintf("taskkill /F /T /PID %s", strconv.Itoa(process.Pid))) + Run(NewRawCommand("killprocess", fmt.Sprintf("taskkill /F /T /PID %s", strconv.Itoa(process.Cmd.Process.Pid)))) time.Sleep(time.Millisecond * 50) return nil } diff --git a/cli/htmgo/tasks/process/process.go b/cli/htmgo/tasks/process/process.go index 736ce1f..a31cd19 100644 --- a/cli/htmgo/tasks/process/process.go +++ b/cli/htmgo/tasks/process/process.go @@ -2,28 +2,49 @@ package process import ( "fmt" + "github.com/maddalax/htmgo/cli/htmgo/internal" "log/slog" "os" "os/exec" "path/filepath" "slices" "strings" + "sync" "time" ) type CmdWithFlags struct { - flags []RunFlag - cmd *exec.Cmd + Flags []RunFlag + Name string + Cmd *exec.Cmd +} + +type RawCommand struct { + Name string + Args string + Flags []RunFlag +} + +func NewRawCommand(name string, args string, flags ...RunFlag) RawCommand { + if name == "" { + name = args + } + c := RawCommand{Name: name, Args: args, Flags: flags} + if c.Flags == nil { + c.Flags = make([]RunFlag, 0) + } + return c } var workingDir string -var commands = make([]CmdWithFlags, 0) +var commands = make(map[string]CmdWithFlags) -func AppendRunning(cmd *exec.Cmd, flags ...RunFlag) { +func AppendRunning(cmd *exec.Cmd, raw RawCommand) { slog.Debug("running", slog.String("command", strings.Join(cmd.Args, " ")), slog.String("dir", cmd.Dir), slog.String("cwd", GetWorkingDir())) - commands = append(commands, CmdWithFlags{flags: flags, cmd: cmd}) + + commands[raw.Name] = CmdWithFlags{Flags: raw.Flags, Name: raw.Name, Cmd: cmd} } func GetWorkingDir() string { @@ -51,19 +72,66 @@ func shouldSkipKilling(flags []RunFlag, skipFlag []RunFlag) bool { return false } +func StartLogger() { + if internal.GetLogLevel() != slog.LevelDebug { + return + } + go func() { + for { + time.Sleep(time.Second * 5) + items := make([]map[string]string, 0) + for _, cmd := range commands { + data := make(map[string]string) + data["command"] = fmt.Sprintf("%s %s", cmd.Cmd.Path, strings.Join(cmd.Cmd.Args, " ")) + if cmd.Cmd.Process != nil { + data["pid"] = fmt.Sprintf("%d", cmd.Cmd.Process.Pid) + } + items = append(items, data) + } + + fmt.Printf("Running processes:\n") + for i, item := range items { + fmt.Printf("%d: %+v\n", i, item) + } + fmt.Printf("\n") + } + }() +} + +func GetProcessByName(name string) *CmdWithFlags { + for _, cmd := range commands { + if cmd.Name == name { + return &cmd + } + } + return nil +} + +func OnShutdown() { + // request for shutdown + for _, cmd := range commands { + if cmd.Cmd != nil && cmd.Cmd.Process != nil { + cmd.Cmd.Process.Signal(os.Interrupt) + } + } + // give it a second + time.Sleep(time.Second * 2) + // force kill + KillAll() +} + func KillAll(skipFlag ...RunFlag) { tries := 0 - updatedCommands := make([]CmdWithFlags, 0) + updatedCommands := make(map[string]CmdWithFlags) for { tries++ allFinished := true for _, cmd := range commands { - if cmd.cmd.Process == nil { + if cmd.Cmd.Process == nil { allFinished = false - if tries > 50 { - args := strings.Join(cmd.cmd.Args, " ") + args := strings.Join(cmd.Cmd.Args, " ") slog.Debug("process is not running after 50 tries, breaking.", slog.String("command", args)) allFinished = true break @@ -72,7 +140,7 @@ func KillAll(skipFlag ...RunFlag) { continue } } else { - updatedCommands = append(updatedCommands, cmd) + updatedCommands[cmd.Name] = cmd } } if allFinished { @@ -80,18 +148,18 @@ func KillAll(skipFlag ...RunFlag) { } } - commands = make([]CmdWithFlags, 0) + commands = make(map[string]CmdWithFlags) for _, command := range updatedCommands { - if command.cmd != nil && command.cmd.Process != nil { - commands = append(commands, command) + if command.Cmd != nil && command.Cmd.Process != nil { + commands[command.Name] = command } } for _, command := range commands { - if shouldSkipKilling(command.flags, skipFlag) { + if shouldSkipKilling(command.Flags, skipFlag) { continue } - err := KillProcess(command.cmd.Process) + err := KillProcess(command) if err != nil { continue } @@ -100,15 +168,15 @@ func KillAll(skipFlag ...RunFlag) { for { finished := true for _, c := range commands { - if c.cmd.Process == nil { + if c.Cmd.Process == nil { continue } - if shouldSkipKilling(c.flags, skipFlag) { + if shouldSkipKilling(c.Flags, skipFlag) { continue } - exists := PidExists(int32(c.cmd.Process.Pid)) + exists := PidExists(int32(c.Cmd.Process.Pid)) if exists { - KillProcess(c.cmd.Process) + KillProcess(c) finished = false } } @@ -121,12 +189,13 @@ func KillAll(skipFlag ...RunFlag) { } } - commands = make([]CmdWithFlags, 0) + commands = make(map[string]CmdWithFlags) slog.Debug("all processes killed\n") } -func RunOrExit(command string) { - _ = Run(command, ExitOnError) +func RunOrExit(command RawCommand) { + command.Flags = append(command.Flags, ExitOnError) + _ = Run(command) } type RunFlag int @@ -137,11 +206,11 @@ const ( KillOnlyOnExit ) -func RunMany(commands []string, flags ...RunFlag) error { +func RunMany(commands ...RawCommand) error { for _, command := range commands { - err := Run(command, flags...) + err := Run(command) if err != nil { - if slices.Contains(flags, ExitOnError) { + if slices.Contains(command.Flags, ExitOnError) { os.Exit(1) } return err @@ -150,19 +219,35 @@ func RunMany(commands []string, flags ...RunFlag) error { return nil } -func Run(command string, flags ...RunFlag) error { - parts := strings.Fields(command) +var mutex = &sync.Mutex{} + +func Run(command RawCommand) error { + mutex.Lock() + + parts := strings.Fields(command.Args) args := make([]string, 0) if len(parts) > 1 { args = parts[1:] } - cmd := exec.Command(parts[0], args...) + path := parts[0] + + existing := GetProcessByName(command.Name) + + if existing != nil { + slog.Debug("process already running, killing it", slog.String("command", command.Name)) + KillProcess(*existing) + time.Sleep(time.Millisecond * 50) + } else { + slog.Debug("no existing process found for %s, safe to run...", slog.String("command", command.Name)) + } + + cmd := exec.Command(path, args...) PrepareCommand(cmd) - if slices.Contains(flags, Silent) { + if slices.Contains(command.Flags, Silent) { cmd.Stdout = nil cmd.Stderr = nil } else { @@ -174,16 +259,21 @@ func Run(command string, flags ...RunFlag) error { cmd.Dir = workingDir } - AppendRunning(cmd, flags...) + AppendRunning(cmd, command) + + mutex.Unlock() err := cmd.Run() slog.Debug("command finished", - slog.String("command", command), + slog.String("command", command.Name), + slog.String("args", command.Args), slog.String("dir", cmd.Dir), slog.String("cwd", GetWorkingDir()), slog.String("error", fmt.Sprintf("%v", err))) + delete(commands, command.Name) + if err == nil { return nil } @@ -192,10 +282,10 @@ func Run(command string, flags ...RunFlag) error { return nil } - if slices.Contains(flags, ExitOnError) { + if slices.Contains(command.Flags, ExitOnError) { slog.Error("Error running command: ", slog.String("error", err.Error()), - slog.String("command", command)) + slog.String("command", command.Name)) os.Exit(1) } diff --git a/cli/htmgo/tasks/reloader/reloader.go b/cli/htmgo/tasks/reloader/reloader.go index 21eddd0..fd5fddc 100644 --- a/cli/htmgo/tasks/reloader/reloader.go +++ b/cli/htmgo/tasks/reloader/reloader.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/fsnotify/fsnotify" "github.com/maddalax/htmgo/cli/htmgo/tasks/astgen" - "github.com/maddalax/htmgo/cli/htmgo/tasks/process" + "github.com/maddalax/htmgo/cli/htmgo/tasks/css" "github.com/maddalax/htmgo/cli/htmgo/tasks/run" "github.com/maddalax/htmgo/cli/htmgo/tasks/util" "log/slog" @@ -60,9 +60,10 @@ type Tasks struct { AstGen bool Run bool Ent bool + Css bool } -func OnFileChange(events []*fsnotify.Event) { +func OnFileChange(version string, events []*fsnotify.Event) { now := time.Now() tasks := Tasks{} @@ -71,11 +72,13 @@ func OnFileChange(events []*fsnotify.Event) { for _, event := range events { c := NewChange(event) - if c.IsGenerated() { + if c.HasAnySuffix(".go~", ".css~") { continue } - slog.Debug("file changed", slog.String("file", c.Name())) + if c.IsGenerated() { + continue + } if c.IsGo() && c.HasAnyPrefix("pages/", "partials/") { tasks.AstGen = true @@ -84,6 +87,7 @@ func OnFileChange(events []*fsnotify.Event) { if c.IsGo() { tasks.Run = true + tasks.Css = true hasTask = true } @@ -92,18 +96,13 @@ func OnFileChange(events []*fsnotify.Event) { hasTask = true } - if c.HasAnySuffix("tailwind.config.js", ".css") { - tasks.Run = true - hasTask = true - } - if c.HasAnyPrefix("ent/schema") { tasks.Ent = true hasTask = true } if hasTask { - slog.Info("file changed", slog.String("file", c.Name())) + slog.Info("file changed", slog.String("version", version), slog.String("file", c.Name())) } } @@ -122,6 +121,15 @@ func OnFileChange(events []*fsnotify.Event) { }() } + if tasks.Css { + deps = append(deps, func() any { + return util.Trace("generate css", func() any { + css.GenerateCss() + return nil + }) + }) + } + if tasks.Ent { deps = append(deps, func() any { return util.Trace("generate ent", func() any { @@ -146,13 +154,6 @@ func OnFileChange(events []*fsnotify.Event) { wg.Wait() - if tasks.Run { - util.Trace("kill all processes", func() any { - process.KillAll(process.KillOnlyOnExit) - return nil - }) - } - if tasks.Run { go run.Server() } diff --git a/cli/htmgo/tasks/run/build.go b/cli/htmgo/tasks/run/build.go index 47fb10c..e468072 100644 --- a/cli/htmgo/tasks/run/build.go +++ b/cli/htmgo/tasks/run/build.go @@ -14,10 +14,10 @@ func Build() { astgen.GenAst(process.ExitOnError) css.GenerateCss(process.ExitOnError) - process.RunOrExit("mkdir -p ./dist") + process.RunOrExit(process.NewRawCommand("", "mkdir -p ./dist")) if os.Getenv("SKIP_GO_BUILD") != "1" { - process.RunOrExit(fmt.Sprintf("go build -tags prod -o ./dist")) + process.RunOrExit(process.NewRawCommand("", fmt.Sprintf("go build -tags prod -o ./dist"))) } fmt.Printf("Executable built at %s\n", process.GetPathRelativeToCwd("dist")) diff --git a/cli/htmgo/tasks/run/entschema.go b/cli/htmgo/tasks/run/entschema.go index b25c8ac..538caac 100644 --- a/cli/htmgo/tasks/run/entschema.go +++ b/cli/htmgo/tasks/run/entschema.go @@ -7,15 +7,15 @@ import ( ) func EntNewSchema(name string) { - process.RunOrExit("GOWORK=off go run -mod=mod entgo.io/ent/cmd/ent new " + name) + process.RunOrExit(process.NewRawCommand("", "GOWORK=off go run -mod=mod entgo.io/ent/cmd/ent new "+name)) } func EntGenerate() { if dirutil.HasFileFromRoot("ent/schema") { if runtime.GOOS == "windows" { - process.RunOrExit("go generate ./ent") + process.RunOrExit(process.NewRawCommand("ent-generate", "go generate ./ent")) } else { - process.RunOrExit("bash -c GOWORK=off go generate ./ent") + process.RunOrExit(process.NewRawCommand("ent-generate", "bash -c GOWORK=off go generate ./ent")) } } } diff --git a/cli/htmgo/tasks/run/runserver.go b/cli/htmgo/tasks/run/runserver.go index 02116b3..a47f7e9 100644 --- a/cli/htmgo/tasks/run/runserver.go +++ b/cli/htmgo/tasks/run/runserver.go @@ -3,5 +3,5 @@ package run import "github.com/maddalax/htmgo/cli/htmgo/tasks/process" func Server(flags ...process.RunFlag) error { - return process.Run("go run .", flags...) + return process.Run(process.NewRawCommand("run-server", "go run .", flags...)) } diff --git a/cli/htmgo/tasks/run/setup.go b/cli/htmgo/tasks/run/setup.go index 6d7b956..d48d42d 100644 --- a/cli/htmgo/tasks/run/setup.go +++ b/cli/htmgo/tasks/run/setup.go @@ -8,8 +8,8 @@ import ( ) func Setup() { - process.RunOrExit("go mod download") - process.RunOrExit("go mod tidy") + process.RunOrExit(process.NewRawCommand("", "go mod download")) + process.RunOrExit(process.NewRawCommand("", "go mod tidy")) copyassets.CopyAssets() astgen.GenAst(process.ExitOnError) diff --git a/cli/htmgo/watcher.go b/cli/htmgo/watcher.go index 87129eb..6a1036f 100644 --- a/cli/htmgo/watcher.go +++ b/cli/htmgo/watcher.go @@ -2,16 +2,20 @@ package main import ( "github.com/fsnotify/fsnotify" + "github.com/google/uuid" + "github.com/maddalax/htmgo/cli/htmgo/internal" "log" "log/slog" "os" "path/filepath" + "time" ) var ignoredDirs = []string{".git", ".idea", "node_modules", "vendor"} -func startWatcher(cb func(file []*fsnotify.Event)) { +func startWatcher(cb func(version string, file []*fsnotify.Event)) { events := make([]*fsnotify.Event, 0) + debouncer := internal.NewDebouncer(500 * time.Millisecond) defer func() { if r := recover(); r != nil { @@ -34,8 +38,18 @@ func startWatcher(cb func(file []*fsnotify.Event)) { } if event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename) { events = append(events, &event) - cb(events) - events = make([]*fsnotify.Event, 0) + debouncer.Do(func() { + seen := make(map[string]bool) + dedupe := make([]*fsnotify.Event, 0) + for _, e := range events { + if _, ok := seen[e.Name]; !ok { + seen[e.Name] = true + dedupe = append(dedupe, e) + } + } + cb(uuid.NewString()[0:6], dedupe) + events = make([]*fsnotify.Event, 0) + }) } case err, ok := <-watcher.Errors: if !ok { diff --git a/framework/h/app.go b/framework/h/app.go index 4553acf..3fa392f 100644 --- a/framework/h/app.go +++ b/framework/h/app.go @@ -1,9 +1,14 @@ package h import ( + "fmt" "github.com/labstack/echo/v4" "github.com/maddalax/htmgo/framework/hx" "github.com/maddalax/htmgo/framework/service" + "log/slog" + "os/exec" + "runtime" + "time" ) type RequestContext struct { @@ -86,6 +91,25 @@ func (a App) start() { err := a.Echo.Start(port) if err != nil { + // If we are in watch mode, just try to kill any processes holding that port + // and try again + if IsDevelopment() && IsWatchMode() { + slog.Info("Port already in use, trying to kill the process and start again") + if runtime.GOOS == "windows" { + cmd := exec.Command("cmd", "/C", fmt.Sprintf(`for /F "tokens=5" %%i in ('netstat -aon ^| findstr :%s') do taskkill /F /PID %%i`, port)) + cmd.Run() + } else { + cmd := exec.Command("bash", "-c", fmt.Sprintf("kill -9 $(lsof -ti%s)", port)) + cmd.Run() + } + time.Sleep(time.Millisecond * 50) + err = a.Echo.Start(port) + if err != nil { + panic(err) + } + } else { + panic(err) + } panic(err) } } diff --git a/htmgo-site/assets/css/input.css b/htmgo-site/assets/css/input.css deleted file mode 100644 index bd6213e..0000000 --- a/htmgo-site/assets/css/input.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file