@@ -39,37 +39,36 @@ These declarations let refresh know when you would like to kill the stale proces
3939Whatever command after REFRESH is considered your "main" subprocess and the one that is tracked inside of refresh
4040
4141## Embedding into your dev project
42- There can be some uses where you might want to start a watcher internally or for a tool for development refresh provides a function ` NewEngineFromOptions ` which takes an ` engine.Config ` and allows for the ` engine. Start()` function
42+ There can be some uses where you might want to start a watcher internally or for a tool for development refresh provides ` NewEngineFromConfig ` , which takes an ` engine.Config ` and returns an engine you can ` Start() ` .
4343
4444Using refresh as a library also opens the ability to add a [ Callback] ( https://github.com/atterpac/refresh#reload-callback ) function that is called on every FS notification
4545
4646### Structs
4747``` go
4848type Config struct {
49- RootPath string ` toml:"root_path"`
50- BackgroundExec string ` toml:"background_exec" ` // Execute that stays running and is unaffected by any reloads npm run dev for example
51- BackgroundCheck bool ` toml:"background_check "`
52- Ignore Ignore ` toml:"ignore" `
53- ExecList []string ` toml:"exec_list"` // See [Execute Lifecycle](https://github.com/atterpac/refresh#execute-lifecycle)
54- LogLevel string ` toml:"log_level"`
55- Debounce int ` toml:"debounce"`
56- Callback func (*EventCallback) EventHandle
57- Slog *slog.Logger
49+ RootPath string ` toml:"root_path" yaml :"root_path"`
50+ BackgroundStruct process. Execute ` toml:"background" yaml:"background" ` // Execute that stays running and is unaffected by reloads (e.g. npm run dev)
51+ Ignore Ignore ` toml:"ignore" yaml:"ignore "`
52+ ExecStruct []process. Execute ` toml:"executes" yaml:"executes" ` // Preferred: typed executes, see [Execute Lifecycle]
53+ ExecList []string ` toml:"exec_list" yaml:"exec_list" ` // Simpler form, see [Execute Lifecycle]
54+ LogLevel string ` toml:"log_level" yaml :"log_level"`
55+ Debounce int ` toml:"debounce" yaml :"debounce"`
56+ Callback func (*EventCallback) EventHandle
57+ Slog *slog.Logger
5858}
5959
6060type Ignore struct {
61- Dir []string ` toml:"dir"` // Specfic directory to ignore ie; node_modules
62- File []string ` toml:"file"` // Specific file to ignore
63- WatchExten []string ` toml:"extension" ` // Extensions to watch NOT ignore, ie; `*.go, *.js` would ignore any file that is not go or javascript
64- GitIgnore bool ` toml:"git_ignore" ` // When true will check for a .gitignore in the root directory and add all entries to the ignore
61+ Dir []string ` toml:"dir" yaml:"dir" ` // Directories to ignore, e.g. node_modules
62+ File []string ` toml:"file" yaml:"file" ` // Files to ignore
63+ WatchedExten []string ` toml:"watched_extension" yaml:"watched_extension" ` // Extensions to watch; anything else is ignored
64+ IgnoreGit bool ` toml:"git" yaml:"git" ` // When true, .gitignore entries in the root are also ignored
6565}
6666
6767type Execute struct {
68- Cmd string ` toml:"cmd" yaml:"cmd"` // Execute command
69- ChangeDir string ` toml:"dir" yaml:"dir"` // If directory needs to be changed to call this command relative to the root path
70- IsBlocking bool ` toml:"blocking" yaml:"blocking"` // Should the following executes wait for this one to complete
71- IsPrimary bool ` toml:"primary" yaml:"primary"` // Only one primary command can be run at a time
72- DelayNext int ` toml:"delay_next" yaml:"delay_next"` // Delay in milliseconds before running command
68+ Cmd string ` toml:"cmd" yaml:"cmd"` // Command to run
69+ ChangeDir string ` toml:"dir" yaml:"dir"` // Directory to run in, relative to root_path
70+ DelayNext int ` toml:"delay_next" yaml:"delay_next"` // Delay in milliseconds before running
71+ Type ExecuteType ` toml:"type" yaml:"type"` // background | once | blocking | primary
7372}
7473```
7574
@@ -90,45 +89,36 @@ func main () {
9089 Dir: []string {" .git" ," */node_modules" , " !api/*" }, // Ignore .git and any node_modules in the directory or anything not within the api directory
9190 IgnoreGit: true , // .gitignore sitting in the root directory? set this to true to automatially ignore those files
9291 }
93- // Build execute structs
92+ // Build execute structs. Type is one of: background | once | blocking | primary
9493 tidy := engine.Execute {
95- Cmd: " go mod tidy" ,
96- IsBlocking: true , // Next command should wait for this to finish
94+ Cmd: " go mod tidy" ,
95+ Type: engine. Blocking , // Next command waits for this to finish
9796 }
9897 build := engine.Execute {
99- Cmd: " go build -o ./bin/myapp" ,
100- IsBlocking: true , // Wait to kill (next step) until the new binary is built
98+ Cmd: " go build -o ./bin/myapp" ,
99+ Type: engine. Blocking , // Block until the new binary is built before restarting
101100 }
102- // Provided KILL_STALE will tell refresh when you would like to remove the stale process to prepare to launch the new one
103- kill := engine.KILL_STALE
104- // Primary process usually runs your binary
101+ // Primary process usually runs your binary; it is killed and restarted on each reload.
105102 run := engine.Execute {
106- ChangeDir: " ./bin" , // Change directory to call command in
107- Cmd: " ./myapp" ,
108- IsBlocking: false , // Should not block because it doesnt finish until Killed by refresh
109- IsPrimary: true , // This is the main process refersh is rerunning so denoting it as primary
103+ ChangeDir: " ./bin" , // Directory to run the command in (relative to root_path)
104+ Cmd: " ./myapp" ,
105+ Type: engine.Primary ,
110106 }
111- // Create config to pass into refresh .NewEngineFromConfig()
107+ // Create config to pass into engine .NewEngineFromConfig()
112108 config := engine.Config {
113- RootPath: " ./test" ,
114- // Below is ran when a reload is triggered before killing the stale version
109+ RootPath: " ./test" ,
115110 Ignore: ignore,
116- Debounce: 1000 , // Time in ms to ignore repitive reload triggers usually caused by an OS creating multiple write/rename events for a singular change
117- LogLevel: " debug" , // debug | info | warn | error | mute -> surpresses all logs to the stdOut
118- Callback: RefreshCallback, // func(*engine.Callback) refresh.EventHandle {}
119- ExecStruct: []refresh.Execute {tidy, build, kill, run},
120- // Alternatively for easier config but less control over executes
121- // ExecList: []string{"go mod tidy", "go build -o ./myapp", refresh.KILL_EXEC, refresh.REFRESH_EXEC, "./myapp"}
122- // All calls will be blocking with the exception of the call after REFRESH
123- // Both KILL_EXEC and REFRESH_EXEC are **REQUIRED** for refresh to function properly
124- // engine.KILL_EXEC denotes when the stale process should be killed
125- // engine.REFRESH_EXEC denotes the next execute is "primary"
126- Slog: nil , // Optionally provide a slog interface
127- // if nil a default will be provided
128- // If provided stdout will not be piped through refresh
111+ Debounce: 1000 , // Time in ms to coalesce repetitive reload triggers (the last save in a burst wins)
112+ LogLevel: " debug" , // debug | info | warn | error | mute
113+ Callback: RefreshCallback, // func(*engine.EventCallback) engine.EventHandle
114+ ExecStruct: []engine.Execute {tidy, build, run},
115+ // Alternatively, the simpler ExecList form. REFRESH_EXEC marks the command
116+ // after it as the primary process; everything else runs blocking in order.
117+ // ExecList: []string{"go mod tidy", "go build -o ./myapp", engine.REFRESH_EXEC, "./myapp"}
118+ Slog: nil , // Optionally provide your own *slog.Logger; a default is used if nil
129119 }
130120
131- engine , err := refresh .NewEngineFromConfig (config)
121+ engine , err := engine .NewEngineFromConfig (config)
132122 if err != nil {
133123 // Handle err
134124 }
@@ -248,12 +238,28 @@ func ExampleCallback(e refresh.EventCallback) refresh.EventHandle {
248238 return engine.EventContinue
249239}
250240```
241+ ### Logging
242+
243+ Refresh ships with a built-in structured logger. The level is set via the
244+ ` log_level ` config field (` debug | info | warn | error | mute ` ) and can also be
245+ controlled at runtime — these are safe to call from any goroutine:
246+
247+ ``` go
248+ engine.SetLogLevel (" debug" ) // change verbosity live ("mute" suppresses output)
249+ engine.DisableLogs () // mute without losing the configured level
250+ engine.EnableLogs () // resume at the previous level
251+ engine.SetLogger (myLogger) // supply your own *slog.Logger (still controllable)
252+ ```
253+
254+ ` DisableLogs ` /` EnableLogs ` toggle a single switch shared by the whole logger, so
255+ re-enabling restores the previously configured level. Subprocess stdout/stderr
256+ is written straight to the terminal and is not affected by these controls.
257+
251258### Config File
252259
253260If you would prefer to load from a [ config] ( https://github.com/Atterpac/refresh#config-file ) file rather than building the structs you can use
254261``` go
255262engine.NewEngineFromTOML (" path/to/toml" )
256- engine.SetLogger (// Input slog.Logger)
257263```
258264#### Example Config
259265``` toml
@@ -262,11 +268,10 @@ engine.SetLogger(//Input slog.Logger)
262268root_path = " ./"
263269# debug | info(default) | warn | error | mute
264270log_level = " info"
265- # Debounce setting for ignoring reptitive file system notifications
271+ # Debounce setting for coalescing repetitive file system notifications
266272debounce = 1000 # Milliseconds
267- # Sets what files the watcher should ignore
268- background_check = true
269273
274+ # Sets what files the watcher should ignore
270275[config .ignore ]
271276# Ignore follows normal pattern matching including /**/
272277# Directories to ignore
@@ -308,15 +313,6 @@ cmd="./app"
308313primary =true
309314```
310315
311- ### Background Check Callback
312- There are instances where you want to wait for the "build" steps for something like vite or a server connection that could take a varying amount
313- of time to reach a ready state. Refresh adds ` engine.AttachBackgroundCallback() ` which will hault the execute commands until the callback returns
314- true (or false for error and shutting down). This could be used along side a ping to the vite port for example to ensure it is reached before
315- running commands that rely on it. This requires 2 things
316-
317- - A callback function that is ` func() bool ` and returns true when ready and false when errored or exited
318- - Attaching the callback via ` engine.AttachBackgroundCallback() ` prior to running ` engine.Start() `
319-
320316#### Flags
321317This method is possible but not the most verbose and controlled way to use refresh
322318
0 commit comments