Skip to content

Commit

Permalink
Improve TOML executes and bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
atterpac committed Jan 15, 2024
1 parent 72454b5 commit 46401b9
Show file tree
Hide file tree
Showing 23 changed files with 177 additions and 165 deletions.
40 changes: 33 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,30 +269,56 @@ func ExampleCallback(e refresh.EventCallback) refresh.EventHandle {

If you would prefer to load from a [config](https://github.com/Atterpac/refresh#config-file) file rather than building the structs you can use
```go
refresh.NewEngineFromTOML("path/to/toml")
engine.NewEngineFromTOML("path/to/toml")
engine.SetLogger(//Input slog.Logger)
```
#### Example Config
```toml
[config]
# Relative to this files location
root_path = "./"
# ordered list of execs to run including the required KILL_STALE, and REFERSH
exec_list = ["go mod tidy", "go build -o ./app", "KILL_STALE", "REFRESH", "./app"
# debug | info | warn | error | mute
# Defaults to Info if not provided
# debug | info(default) | warn | error | mute
log_level = "info"
# Debounce setting for ignoring reptitive file system notifications
debounce = 1000 # Milliseconds
# Sets what files the watcher should ignore
[config.ignore]
# Ignore follows normal pattern matching including /**/
# Directories to ignore
dir = [".git", "node_modules", "newdir"]
# Files to ignore
file = [".DS_Store", ".gitignore", ".gitkeep", "newfile.go"]
file = [".DS_Store", ".gitignore", ".gitkeep", "newfile.go", "*ignoreme*"]
# File extensions to watch
watched_extensions = [".db", ".sqlite"]
watched_extensions = ["*.go"]
# Add .gitignore paths to ignore
git_ignore = true

# Runs process in the background and doesnt restart when a refresh is triggered
[config.background]
cmd="vite dev"

# Execute structs
# dir is used to change the working directory to execute into
# cmd is the command to be executed
# primary denotes this is the process refresh should be tracking to kill on reload
# blocking denotes wether the next execute should wait for it to complete ie; build the application and when its done run it
# KILL_STALE is required to be ran at any point before the primary is executed this kills the previous version of the application
[[config.executes]]
cmd="go mod tidy"
primary=false
blocking=true

[[config.executes]]
cmd="go build -o ./bin/app"
blocking=true

[[config.executes]]
cmd="KILL_STALE"

[[config.executes]]
dir="./bin"
cmd="./app"
primary=true
```

### Alternatives
Expand Down
2 changes: 1 addition & 1 deletion cmd/refresh/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func main() {
var version string = "0.3.1"
var version string = "0.4.0"

var rootPath string
var execCommand string
Expand Down
12 changes: 6 additions & 6 deletions engine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ import (
)

type Config struct {
RootPath string `toml:"root_path"`
BackgroundExec string `toml:"background_exec"`
BackgroundStruct Execute
Ignore Ignore `toml:"ignore"`
ExecList []string `toml:"exec_list"`
ExecStruct []Execute
RootPath string `toml:"root_path"`
BackgroundStruct Execute `toml:"background"`
Ignore Ignore `toml:"ignore"`
ExecStruct []Execute `toml:"executes"`
ExecList []string `toml:"exec_list"`
ignoreMap ignoreMap
LogLevel string `toml:"log_level"`
Debounce int `toml:"debounce"`
Expand Down Expand Up @@ -47,6 +46,7 @@ func (engine *Engine) verifyConfig() {
slog.Debug("Config Verified")
// Change directory executes are called in to match root directory
cleaned := cleanDirectory(engine.Config.RootPath)
slog.Info("Changing Working Directory", "dir", cleaned)
changeWorkingDirectory(cleaned)
}

Expand Down
14 changes: 4 additions & 10 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,14 @@ type Engine struct {
}

func (engine *Engine) Start() {
if engine.Config.Slog == nil {
engine.Config.Slog = newLogger(engine.Config.LogLevel)
engine.Config.externalSlog = false
} else {
engine.Config.externalSlog = true
}
engine.Config.Slog = newLogger(engine.Config.LogLevel)
engine.Config.externalSlog = false
slog.SetDefault(engine.Config.Slog)
slog.Info("Refresh Start")
if engine.Config.Ignore.IgnoreGit {
engine.Config.ignoreMap.git = readGitIgnore(engine.Config.RootPath)
}
if engine.Config.BackgroundStruct.Cmd != "" {
go backgroundExec(engine.Config.BackgroundStruct.Cmd)
}
go backgroundExec(engine.Config.BackgroundExec)
go backgroundExec(engine.Config.BackgroundStruct.Cmd)
go engine.reloadProcess()
engine.watch()
}
Expand Down Expand Up @@ -81,6 +74,7 @@ func NewEngineFromTOML(confPath string) *Engine {
engine := Engine{}
engine.readConfigFile(confPath)
engine.Config.ignoreMap = convertToIgnoreMap(engine.Config.Ignore)
engine.Config.externalSlog = false
engine.verifyConfig()
return &engine
}
103 changes: 21 additions & 82 deletions engine/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
)

type Execute struct {
Cmd string // Execute command
ChangeDir string // If directory needs to be changed to call this command relative to the root path
IsBlocking bool // Should the following executes wait for this one to complete
IsPrimary bool // Only one primary command can be run at a time
Cmd string `toml:"cmd"` // Execute command
ChangeDir string `toml:"dir"` // If directory needs to be changed to call this command relative to the root path
IsBlocking bool `toml:"blocking"` // Should the following executes wait for this one to complete
IsPrimary bool `toml:"primary"` // Only one primary command can be run at a time
process *os.Process // Stores the Exec.Start() process
}

Expand All @@ -25,6 +25,7 @@ var KILL_STALE = Execute{

var REFRESH_EXEC = "REFRESH"
var KILL_EXEC = "KILL_STALE"
var firstRun = true

func (ex *Execute) run(engine *Engine) error {
var err error
Expand All @@ -43,11 +44,11 @@ func (ex *Execute) run(engine *Engine) error {
if ex.IsPrimary {
slog.Debug("Reloading Process")
engine.Process, err = engine.startPrimary(ex.Cmd)
slog.Info("Primary Process Started", "pid", engine.Process.Pid)
if err != nil {
slog.Error(fmt.Sprintf("Starting Run command: %s", err.Error()))
os.Exit(1)
}
slog.Debug("Sucessfull refresh")
if restoreDir != "" {
slog.Info("Restoring working Dir")
changeWorkingDirectory(restoreDir)
Expand All @@ -58,7 +59,10 @@ func (ex *Execute) run(engine *Engine) error {
case "":
return nil
case "KILL_STALE":
slog.Debug("No process found to kill")
if firstRun {
firstRun = false
return nil
}
if engine.isRunning() {
slog.Debug("Killing Stale Version")
ok := killProcess(engine.Process)
Expand All @@ -72,23 +76,10 @@ func (ex *Execute) run(engine *Engine) error {
}
}
default:
slog.Debug(fmt.Sprintf("Running Exec Command: %s", ex.Cmd))
commandSlice := generateExec(ex.Cmd)
cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Start()
err := execFromString(ex.Cmd, ex.IsBlocking)
if err != nil {
return err
slog.Error("Running Execute", "command:", ex.Cmd)
}
ex.process = cmd.Process
if ex.IsBlocking {
err = cmd.Wait()
if err != nil {
return err
}
}
slog.Debug(fmt.Sprintf("Complete Exec Command: %s", ex.Cmd))
}
if restoreDir != "" {
slog.Info("Restoring working Dir")
Expand All @@ -97,82 +88,30 @@ func (ex *Execute) run(engine *Engine) error {
return nil
}

func (engine *Engine) execFromList() error {
var nextPrimary bool
var err error
if engine.Config.ExecList == nil {
return nil
}
for _, exe := range engine.Config.ExecList {
slog.Debug("is Primary?", fmt.Sprintf("%v", exe), nextPrimary)
if nextPrimary {
slog.Debug("Reloading Process")
engine.Process, err = engine.startPrimary(exe)
if err != nil {
slog.Error(fmt.Sprintf("Starting Run command: %s", err.Error()))
os.Exit(1)
}
slog.Debug("Sucessfull refresh")
nextPrimary = false
}
switch exe {
case "":
return nil
case "REFRESH":
nextPrimary = true
case "KILL_STALE":
slog.Debug("No process found to kill")
if engine.isRunning() {
slog.Debug("Killing Stale Version")
ok := killProcess(engine.Process)
if !ok {
slog.Error("Releasing stale process")
}
if engine.ProcessLogPipe != nil {
slog.Debug("Closing log pipe")
engine.ProcessLogPipe.Close()
engine.ProcessLogPipe = nil
}
}
default:
slog.Debug(fmt.Sprintf("Running Exec Command: %s", exe))
commandSlice := generateExec(exe)
cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Start()
if err != nil {
return err
}
err = cmd.Wait()
if err != nil {
slog.Error("Running Execute","command:", exe)
}
slog.Debug(fmt.Sprintf("Complete Exec Command: %s", exe))
}
}
return nil
}

func backgroundExec(runString string) {
func backgroundExec(runString string) {
commandSlice := generateExec(runString)
cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
var out, err bytes.Buffer
// Let Process run in background
cmd.Stdout = &out
cmd.Stderr = &err
cmd.Start()
slog.Debug(fmt.Sprintf("Complete Exec Command: %s", runString))
}

func execFromString(runString string) error {
func execFromString(runString string, block bool) error {
commandSlice := generateExec(runString)
cmd := exec.Command(commandSlice[0], commandSlice[1:]...)
// Let Process run in background
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
return err
if block {
err = cmd.Wait()
if err != nil {
slog.Error("Running Execute", "command:", runString)
return err
}
}
return nil
}
Expand Down
72 changes: 48 additions & 24 deletions engine/ignore.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package engine

import (
"fmt"
"log/slog"
"path/filepath"
"strings"
Expand All @@ -22,31 +21,56 @@ type ignoreMap struct {
}

// Runs all ignore checks to decide if reload should happen
func (i *ignoreMap) checkIgnore(path string) bool {
slog.Debug("Checking Ignore")
basePath := filepath.Base(path)
if isTmp(basePath) {
// func (i *ignoreMap) checkIgnore(path string) bool {
// slog.Debug("Checking Ignore")
// basePath := filepath.Base(path)
// if isTmp(basePath) {
// return true
// }
// if isIgnoreDir(path, i.dir) {
// return true
// }
// dir := checkIgnoreMap(path, i.dir)
// file := checkIgnoreMap(path, i.file)
// git := checkIgnoreMap(path, i.git)
// return dir || file || git
// return i.shouldIgnore(path)
// }

func (i *Ignore) shouldIgnore(path string) bool {
slog.Debug("New Ignore Check")
if isIgnoreDir(path, i.Dir) {
slog.Debug("Ignore Dir")
return true
}
if patternMatch(path, i.Dir) {
slog.Debug("Matched Dir")
return true
}
if isIgnoreDir(path, i.dir) {
if patternMatch(path, i.File) {
slog.Debug("Matched File")
return true
}
dir := checkIgnoreMap(path, i.dir)
file := checkIgnoreMap(path, i.file)
git := checkIgnoreMap(path, i.git)
return dir || file || git
}

func checkIgnoreMap(path string, rules map[string]struct{}) bool {
slog.Debug(fmt.Sprintf("Checking map: %v for %s", rules, path))
_, ok := rules[path]
return mapHasItems(rules) && patternMatch(path, rules) || ok
if i.isWatchedExtension(path) {
slog.Debug("Watched Extension")
return false
}
return true
}

func checkExtension(path string, rules map[string]struct{}) bool {
slog.Debug(fmt.Sprintf("Checking Extension map: %v for %s", rules, path))
return patternMatch(path, rules)
func (i *Ignore) isWatchedExtension(path string) bool {
return patternMatch(path, i.WatchedExten)
}
// func checkIgnoreMap(path string, rules map[string]struct{}) bool {
// slog.Debug(fmt.Sprintf("Checking map: %v for %s", rules, path))
// _, ok := rules[path]
// return mapHasItems(rules) && patternMatch(path, rules) || ok
// }
//
// func checkExtension(path string, rules map[string]struct{}) bool {
// slog.Debug(fmt.Sprintf("Checking Extension map: %v for %s", rules, path))
// return patternMatch(path, rules)
// }

func mapHasItems(m map[string]struct{}) bool {
return len(m) >= 0
Expand All @@ -58,13 +82,13 @@ func isTmp(path string) bool {
}

// Checks if path contains any directories in the ignore directory config
func isIgnoreDir(path string, Dirmap map[string]struct{}) bool {
func isIgnoreDir(path string, rules []string) bool {
dirs := strings.Split(path, string(filepath.Separator))
for _, dir := range dirs {
_, ok := Dirmap[dir]
if ok {
slog.Debug(fmt.Sprintf("Matched: %s with %s", path, dir))
return true
for _, rule := range rules {
if dir == rule {
return true
}
}
}
return false
Expand Down
Loading

0 comments on commit 46401b9

Please sign in to comment.