* Refactor CLI * Add config:print command * Add diagnose command * Allow including other files in config * Watch for file changes and automatically restart server
122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
package glance
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
func Main() int {
|
|
options, err := parseCliOptions()
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return 1
|
|
}
|
|
|
|
switch options.intent {
|
|
case cliIntentServe:
|
|
if err := serveApp(options.configPath); err != nil {
|
|
fmt.Println(err)
|
|
return 1
|
|
}
|
|
case cliIntentConfigValidate:
|
|
contents, _, err := parseYAMLIncludes(options.configPath)
|
|
if err != nil {
|
|
fmt.Printf("failed to parse config file: %v\n", err)
|
|
return 1
|
|
}
|
|
|
|
if _, err := newConfigFromYAML(contents); err != nil {
|
|
fmt.Printf("config file is invalid: %v\n", err)
|
|
return 1
|
|
}
|
|
case cliIntentConfigPrint:
|
|
contents, _, err := parseYAMLIncludes(options.configPath)
|
|
if err != nil {
|
|
fmt.Printf("failed to parse config file: %v\n", err)
|
|
return 1
|
|
}
|
|
|
|
fmt.Println(string(contents))
|
|
case cliIntentDiagnose:
|
|
runDiagnostic()
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func serveApp(configPath string) error {
|
|
exitChannel := make(chan struct{})
|
|
// the onChange method gets called at most once per 500ms due to debouncing so we shouldn't
|
|
// need to use atomic.Bool here unless newConfigFromYAML is very slow for some reason
|
|
hadValidConfigOnStartup := false
|
|
var stopServer func() error
|
|
|
|
onChange := func(newContents []byte) {
|
|
if stopServer != nil {
|
|
log.Println("Config file changed, attempting to restart server")
|
|
}
|
|
|
|
config, err := newConfigFromYAML(newContents)
|
|
if err != nil {
|
|
log.Printf("Config file is invalid: %v", err)
|
|
|
|
if !hadValidConfigOnStartup {
|
|
close(exitChannel)
|
|
}
|
|
|
|
return
|
|
} else if !hadValidConfigOnStartup {
|
|
hadValidConfigOnStartup = true
|
|
}
|
|
|
|
app := newApplication(config)
|
|
|
|
if stopServer != nil {
|
|
if err := stopServer(); err != nil {
|
|
log.Printf("Error while trying to stop server: %v", err)
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
var startServer func() error
|
|
startServer, stopServer = app.Server()
|
|
|
|
if err := startServer(); err != nil {
|
|
log.Printf("Failed to start server: %v", err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
onErr := func(err error) {
|
|
log.Printf("Error watching config files: %v", err)
|
|
}
|
|
|
|
configContents, configIncludes, err := parseYAMLIncludes(configPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse config file: %w", err)
|
|
}
|
|
|
|
stopWatching, err := configFilesWatcher(configPath, configContents, configIncludes, onChange, onErr)
|
|
if err == nil {
|
|
defer stopWatching()
|
|
} else {
|
|
log.Printf("Error starting file watcher, config file changes will require a manual restart. (%v)", err)
|
|
|
|
config, err := newConfigFromYAML(configContents)
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse config file: %w", err)
|
|
}
|
|
|
|
app := newApplication(config)
|
|
|
|
startServer, _ := app.Server()
|
|
if err := startServer(); err != nil {
|
|
return fmt.Errorf("failed to start server: %w", err)
|
|
}
|
|
}
|
|
|
|
<-exitChannel
|
|
return nil
|
|
}
|