diff --git a/pkg/alvu/alvu.go b/pkg/alvu/alvu.go index b62d470..b7ebd7b 100644 --- a/pkg/alvu/alvu.go +++ b/pkg/alvu/alvu.go @@ -51,6 +51,13 @@ type AlvuConfig struct { // Internals logger Logger hookHandler *Hooks + watcher *Watcher +} + +func (ac *AlvuConfig) Rebuild(path string) { + ac.logger.Info(fmt.Sprintf("Changed: %v, Recompiling.", path)) + err := ac.Build() + ac.logger.Error(err.Error()) } func (ac *AlvuConfig) Run() error { @@ -58,6 +65,30 @@ func (ac *AlvuConfig) Run() error { logPrefix: "[alvu]", } + if ac.Serve { + ac.watcher = NewWatcher() + ac.watcher.logger = ac.logger + go func(ac *AlvuConfig) { + for path := range ac.watcher.recompile { + ac.logger.Info(fmt.Sprintf("Changed: %v, recompiling...", path)) + ac.Build() + } + }(ac) + } + + err := ac.Build() + if err != nil { + return err + } + + if ac.Serve { + ac.watcher.Start() + } + + return ac.StartServer() +} + +func (ac *AlvuConfig) Build() error { hooksHandler := Hooks{ ac: *ac, } @@ -77,18 +108,24 @@ func (ac *AlvuConfig) Run() error { }, } - filesToProcess, err := ac.ReadDir(filepath.Join(ac.RootPath, "pages")) + pageDir := filepath.Join(ac.RootPath, "pages") + publicDir := filepath.Join(ac.RootPath, "public") + + filesToProcess, err := ac.ReadDir(pageDir) if err != nil { return err } ac.logger.Debug(fmt.Sprintf("filesToProcess: %v", filesToProcess)) - publicFiles, err := ac.ReadDir(filepath.Join(ac.RootPath, "public")) + publicFiles, err := ac.ReadDir(publicDir) if err != nil { return err } + ac.watcher.AddDir(pageDir) + ac.watcher.AddDir(publicDir) + normalizedFiles, err := runTransfomers(filesToProcess, ac) if err != nil { return err @@ -105,12 +142,7 @@ func (ac *AlvuConfig) Run() error { } ac.HandlePublicFiles(publicFiles) - err = ac.FlushFiles(processedFiles) - if err != nil { - return err - } - - return ac.StartServer() + return ac.FlushFiles(processedFiles) } func (ac *AlvuConfig) ReadLayout() string { diff --git a/pkg/alvu/hooks.go b/pkg/alvu/hooks.go index c300f48..ea1f1c3 100644 --- a/pkg/alvu/hooks.go +++ b/pkg/alvu/hooks.go @@ -31,6 +31,8 @@ type Hooks struct { ac AlvuConfig collection []*HookSource forSpecificFiles map[string][]*HookSource + + _legacyTransformLogSent bool } type HookedFile struct { @@ -232,7 +234,10 @@ func (h *Hooks) ProcessFile(file transformers.TransformedFile) (hookedFile Hooke if fromPlug["transform"] != nil { hookedFile.transform = fmt.Sprintf("%v", fromPlug["transform"]) } else { - h.ac.logger.Warning("Auto transformation of content returned from the hooks will be removed in v0.3,\n please return a `transform` property from the hooks instead.") + if !h._legacyTransformLogSent { + h.ac.logger.Warning("Auto transformation of content returned from the hooks will be removed in v0.3,\n please return a `transform` property from the hooks instead.") + h._legacyTransformLogSent = true + } hookedFile.transform = ".md" } diff --git a/pkg/alvu/watcher.go b/pkg/alvu/watcher.go new file mode 100644 index 0000000..fe5cb0e --- /dev/null +++ b/pkg/alvu/watcher.go @@ -0,0 +1,54 @@ +package alvu + +import ( + "fmt" + "os" + + "github.com/barelyhuman/go/poller" +) + +type Watcher struct { + poller *poller.Poller + logger Logger + recompile chan string +} + +type HookFn func(path string) + +func NewWatcher() *Watcher { + return &Watcher{ + poller: poller.NewPollWatcher(2000), + recompile: make(chan string, 1), + } +} + +func (p *Watcher) AddDir(path string) { + p.poller.Add(path) +} + +func (p *Watcher) Start() { + go p.poller.Start() + go func() { + for { + select { + case evt := <-p.poller.Events: + _, err := os.Stat(evt.Path) + + p.logger.Debug(fmt.Sprintf("Change Event: %v", evt)) + + // Do nothing if the file doesn't exit, just continue + if err != nil { + if os.IsNotExist(err) { + continue + } + p.logger.Error(err.Error()) + } + + p.recompile <- evt.Path + continue + case err := <-p.poller.Errors: + p.logger.Error(err.Error()) + } + } + }() +} diff --git a/transformers/markdown/markdown.go b/transformers/markdown/markdown.go index 01c0446..3ddd4ad 100644 --- a/transformers/markdown/markdown.go +++ b/transformers/markdown/markdown.go @@ -120,8 +120,15 @@ func (rlr *relativeLinkRewriter) Transform(doc *ast.Document, reader text.Reader }) } +// TODO: remove in v0.3 +var _warningPrinted bool = false + // TODO: remove in v0.3 func printMetaLinkWarning() { + if _warningPrinted { + return + } + _warningPrinted = true warning := "{{.Meta.BaseURL}} is no more needed in markdown files, links will be rewritten automatically.\n Use root first links, eg: pages/docs/some-topic.md would be linked as /docs/some-topic" cs := color.ColorString{} cs.Reset(" ").Yellow(warning)