diff --git a/internal/glance/config.go b/internal/glance/config.go index 7b3377b..0d424a2 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -242,7 +242,7 @@ func configFilesWatcher( // needed for lastContents and lastIncludes because they get updated in multiple goroutines mu := sync.Mutex{} - checkForContentChangesBeforeCallback := func() { + parseAndCompareBeforeCallback := func() { currentContents, currentIncludes, err := parseYAMLIncludes(mainFilePath) if err != nil { onErr(fmt.Errorf("parsing main file contents for comparison: %w", err)) @@ -268,15 +268,22 @@ func configFilesWatcher( const debounceDuration = 500 * time.Millisecond var debounceTimer *time.Timer - debouncedCallback := func() { + debouncedParseAndCompareBeforeCallback := func() { if debounceTimer != nil { debounceTimer.Stop() debounceTimer.Reset(debounceDuration) } else { - debounceTimer = time.AfterFunc(debounceDuration, checkForContentChangesBeforeCallback) + debounceTimer = time.AfterFunc(debounceDuration, parseAndCompareBeforeCallback) } } + deleteLastInclude := func(filePath string) { + mu.Lock() + defer mu.Unlock() + fileAbsPath, _ := filepath.Abs(filePath) + delete(lastIncludes, fileAbsPath) + } + go func() { for { select { @@ -285,16 +292,33 @@ func configFilesWatcher( return } if event.Has(fsnotify.Write) { - debouncedCallback() - } else if event.Has(fsnotify.Remove) { - func() { - mu.Lock() - defer mu.Unlock() - fileAbsPath, _ := filepath.Abs(event.Name) - delete(lastIncludes, fileAbsPath) - }() + debouncedParseAndCompareBeforeCallback() + } else if event.Has(fsnotify.Rename) { + // on linux the file will no longer be watched after a rename, on windows + // it will continue to be watched with the new name but we have no access to + // the new name in this event in order to stop watching it manually and match the + // behavior in linux, may lead to weird unintended behaviors on windows as we're + // only handling renames from linux's perspective + // see https://github.com/fsnotify/fsnotify/issues/255 - debouncedCallback() + // remove the old file from our manually tracked includes, calling + // debouncedParseAndCompareBeforeCallback will re-add it if it's still + // required after it triggers + deleteLastInclude(event.Name) + + // wait for file to maybe get created again + // see https://github.com/glanceapp/glance/pull/358 + for i := 0; i < 10; i++ { + if _, err := os.Stat(event.Name); err == nil { + break + } + time.Sleep(200 * time.Millisecond) + } + + debouncedParseAndCompareBeforeCallback() + } else if event.Has(fsnotify.Remove) { + deleteLastInclude(event.Name) + debouncedParseAndCompareBeforeCallback() } case err, isOpen := <-watcher.Errors: if !isOpen {