diff --git a/.gitignore b/.gitignore index 73313bc..cb049df 100644 --- a/.gitignore +++ b/.gitignore @@ -21,14 +21,10 @@ # CI bin/ -assets/reveal +assets/reveal/ pkged.go -# binaries -goveal -!goveal/ - # gorelease dist/ diff --git a/Makefile b/Makefile index 408b963..330a342 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ VERSION = $(shell git describe --dirty --tags --always) -REPO = github.com/baez90/go-reveal-slides +REPO = github.com/baez90/goveal BUILD_PATH = $(REPO)/cmd/goveal PKGS = $(shell go list ./... | grep -v /vendor/) TEST_PKGS = $(shell find . -type f -name "*_test.go" -printf '%h\n' | sort -u) diff --git a/README.md b/README.md index 0393f32..0cd22de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Goveal -[![CircleCI](https://circleci.com/gh/baez90/go-reveal-slides.svg?style=svg)](https://circleci.com/gh/baez90/go-reveal-slides) +[![Actions Status](https://github.com/baez90/goveal/workflows/Go/badge.svg)](https://github.com/baez90/goveal/actions) Goveal is very small an very simple tool that reads Markdown from a given file, renders it into a HTML template and serves it as local HTTP server. Right now Goveal uses Reveal.js 4.0.2 to create presentations and therefore also includes all features of Reveal.js 4.0.2. diff --git a/Taskfile.yml b/Taskfile.yml index d22e140..ee68cb4 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -6,7 +6,7 @@ vars: BINARY_NAME: goveal OUT_DIR: ./out GO_BUILD_ARGS: -ldflags="-w -s" - CMD_PACKAGE: github.com/baez90/go-reveal-slides/cmd/goveal + CMD_PACKAGE: github.com/baez90/goveal/cmd/goveal emv: CGO_ENABLED: 0 diff --git a/assets/template/reveal-markdown.tmpl b/assets/template/reveal-markdown.tmpl index b541436..cb1228b 100644 --- a/assets/template/reveal-markdown.tmpl +++ b/assets/template/reveal-markdown.tmpl @@ -90,7 +90,7 @@ {{ if .Reveal.FilesToMonitor }} {{ range $idx, $file := .Reveal.FilesToMonitor }} - subscribeForUpdates("/{{ trimPrefix "/" $file }}") + subscribeForUpdates("/{{ $file }}") {{ end }} {{ end }} diff --git a/cmd/goveal/main.go b/cmd/goveal/main.go index 4a3430f..bca3283 100644 --- a/cmd/goveal/main.go +++ b/cmd/goveal/main.go @@ -15,8 +15,8 @@ package main import ( - _ "github.com/baez90/go-reveal-slides" - "github.com/baez90/go-reveal-slides/internal/app/cmd" + _ "github.com/baez90/goveal" + "github.com/baez90/goveal/internal/app/cmd" ) func main() { diff --git a/examples/goveal.yaml b/examples/goveal.yaml index 94b3765..8187d56 100644 --- a/examples/goveal.yaml +++ b/examples/goveal.yaml @@ -1,9 +1,9 @@ theme: night -code-theme: monokai -horizontal-separator: === -vertical-separator: --- +codeTheme: monokai +horizontalSeparator: === +verticalSeparator: --- transition: fade stylesheets: - - examples/custom.css + - custom.css filesToMonitor: - - examples/**/*.css \ No newline at end of file + - ./**/*.css \ No newline at end of file diff --git a/go.mod b/go.mod index 560676a..dfcef5d 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/baez90/go-reveal-slides +module github.com/baez90/goveal go 1.15 @@ -11,7 +11,7 @@ require ( github.com/gobuffalo/here v0.6.2 // indirect github.com/google/uuid v1.1.2 // indirect github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.11 // indirect + github.com/imdario/mergo v0.3.11 github.com/markbates/pkger v0.17.1 github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 diff --git a/internal/app/cmd/root.go b/internal/app/cmd/root.go index b138702..47b5fb2 100644 --- a/internal/app/cmd/root.go +++ b/internal/app/cmd/root.go @@ -17,8 +17,9 @@ package cmd import ( "fmt" "os" + "path/filepath" - "github.com/baez90/go-reveal-slides/internal/app/rendering" + "github.com/baez90/goveal/internal/app/rendering" "github.com/fsnotify/fsnotify" "github.com/mitchellh/go-homedir" @@ -27,21 +28,10 @@ import ( "github.com/spf13/viper" ) -const ( - defaultTheme string = "white" -) - var ( - cfgFile string - theme string - codeTheme string - transition string - navigationMode string - horizontalSeparator string - verticalSeparator string - slideNumberVisibility string - slideNumberFormat string - rootCmd = &cobra.Command{ + cfgFile string + workingDir string + rootCmd = &cobra.Command{ Use: "goveal", Short: "goveal is a small reveal.js server", Long: `goveal is a single static binary to host your reveal.js based markdown presentation. @@ -61,18 +51,18 @@ func Execute() { } func init() { - cobra.OnInitialize(initConfig) cobra.OnInitialize(initLogging) + cobra.OnInitialize(initConfig) + + var err error + workingDir, err = os.Getwd() + if err != nil { + fmt.Println(err) + os.Exit(1) + } - rootCmd.PersistentFlags().StringVar(&theme, "theme", defaultTheme, "reveal.js theme to use") - rootCmd.PersistentFlags().StringVar(&codeTheme, "code-theme", "monokai", "name of the code theme to use for highlighting") - rootCmd.PersistentFlags().StringVar(&transition, "transition", "none", "transition effect to use") - rootCmd.PersistentFlags().StringVar(&navigationMode, "navigationMode", "default", "determine the navigation mode to use ['default', 'linear', 'grid']") - rootCmd.PersistentFlags().StringVar(&horizontalSeparator, "horizontal-separator", "===", "horizontal separator in slides") - rootCmd.PersistentFlags().StringVar(&verticalSeparator, "vertical-separator", "---", "vertical separator in slides") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.go-reveal-slides.yaml)") - rootCmd.PersistentFlags().StringVar(&slideNumberVisibility, "slide-number-visibility", "all", "where should slide numbers be visible ['all', 'speaker', 'print']") - rootCmd.PersistentFlags().StringVar(&slideNumberFormat, "slide-number-format", "h.v", "Format of the slide number ['h.v', 'h/v', 'c', 'c/t']") + rootCmd.PersistentFlags().StringVar(&workingDir, "working-dir", workingDir, "working directory to use") } func initLogging() { @@ -83,6 +73,24 @@ func initLogging() { // initConfig reads in config file and ENV variables if set. func initConfig() { + var err error + if workingDir, err = filepath.Abs(workingDir); err != nil { + log.Warnf("Failed to determine absolute path for working dir %s: %v", workingDir, err) + return + } + + var cwd string + if cwd, err = os.Getwd(); err != nil { + log.Warnf("Failed to determine current working directory") + return + } + + if cwd != workingDir { + if err = os.Chdir(workingDir); err != nil { + log.Warnf("Failed to change working directory to %s", workingDir) + } + } + if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) @@ -95,14 +103,9 @@ func initConfig() { viper.AddConfigPath(home) } - cwd, err := os.Getwd() - if err != nil { - log.Infof("Failed to determine current working directory: %v", err) - } else { - viper.AddConfigPath(cwd) - } - + viper.AddConfigPath(workingDir) viper.SetConfigName("goveal") + viper.SetConfigType("yaml") } viper.AutomaticEnv() // read in environment variables that match @@ -119,10 +122,6 @@ func initConfig() { }) } - if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { - log.Errorf("Failed to bind flags to viper") - } - + params.WorkingDirectory = workingDir params.Load() - } diff --git a/internal/app/cmd/serve.go b/internal/app/cmd/serve.go index 91e7675..fab49ab 100644 --- a/internal/app/cmd/serve.go +++ b/internal/app/cmd/serve.go @@ -21,7 +21,7 @@ import ( "os/exec" "runtime" - "github.com/baez90/go-reveal-slides/internal/app/server" + "github.com/baez90/goveal/internal/app/server" "github.com/spf13/cobra" log "github.com/sirupsen/logrus" diff --git a/internal/app/rendering/reveal_params.go b/internal/app/rendering/reveal_params.go index 34b94cb..711dbf7 100644 --- a/internal/app/rendering/reveal_params.go +++ b/internal/app/rendering/reveal_params.go @@ -16,25 +16,45 @@ package rendering import ( "github.com/bmatcuk/doublestar/v2" + "github.com/imdario/mergo" "github.com/spf13/viper" + "path" + "path/filepath" +) + +var ( + defaultParams = RevealParams{ + Theme: "white", + CodeTheme: "vs", + Transition: "None", + NavigationMode: "default", + HorizontalSeparator: "===", + VerticalSeparator: "---", + SlideNumberVisibility: "all", + SlideNumberFormat: "h.v", + StyleSheets: make([]string, 0), + FilesToMonitor: make([]string, 0), + } ) type RevealParams struct { Theme string `mapstructure:"theme"` - CodeTheme string `mapstructure:"code-theme"` + CodeTheme string `mapstructure:"codeTheme"` Transition string `mapstructure:"transition"` NavigationMode string `mapstructure:"navigationMode"` - HorizontalSeparator string `mapstructure:"horizontal-separator"` - VerticalSeparator string `mapstructure:"vertical-separator"` - SlideNumberVisibility string `mapstructure:"slide-number-visibility"` - SlideNumberFormat string `mapstructure:"slide-number-format"` + HorizontalSeparator string `mapstructure:"horizontalSeparator"` + VerticalSeparator string `mapstructure:"verticalSeparator"` + SlideNumberVisibility string `mapstructure:"slideNumberVisibility"` + SlideNumberFormat string `mapstructure:"slideNumberFormat"` StyleSheets []string `mapstructure:"stylesheets"` FilesToMonitor []string `mapstructure:"filesToMonitor"` + WorkingDirectory string `mapstructure:"working-dir"` } -func (params *RevealParams) Load() { +func (params *RevealParams) Load() error { _ = viper.Unmarshal(params) expandGlobs(params) + return mergo.Merge(params, &defaultParams) } func expandGlobs(params *RevealParams) { @@ -43,10 +63,24 @@ func expandGlobs(params *RevealParams) { for _, f := range params.FilesToMonitor { var err error + f, err = filepath.Abs(f) + if err != nil { + continue + } + var matches []string if matches, err = doublestar.Glob(f); err != nil { continue } + + for idx := range matches { + if relative, err := filepath.Rel(params.WorkingDirectory, matches[idx]); err != nil { + continue + } else { + matches[idx] = path.Join("/", relative) + } + } + allFiles = append(allFiles, matches...) } params.FilesToMonitor = allFiles diff --git a/internal/app/routing/no_cache_handler.go b/internal/app/routing/no_cache_handler.go index c19a320..cb05a4e 100644 --- a/internal/app/routing/no_cache_handler.go +++ b/internal/app/routing/no_cache_handler.go @@ -2,6 +2,7 @@ package routing import ( "net/http" + "strings" "time" ) @@ -23,8 +24,21 @@ var etagHeaders = []string{ "If-Unmodified-Since", } -func NoCache(h http.Handler) http.Handler { +func NoCache(h http.Handler, pathsToDisableCache []string) http.Handler { + + pathLookup := make(map[string]bool) + + for idx := range pathsToDisableCache { + pathLookup[strings.ToLower(pathsToDisableCache[idx])] = true + } + fn := func(w http.ResponseWriter, r *http.Request) { + + if _, shouldBeHandled := pathLookup[strings.ToLower(r.URL.Path)]; !shouldBeHandled { + h.ServeHTTP(w, r) + return + } + // Delete any ETag headers that may have been set for _, v := range etagHeaders { if r.Header.Get(v) != "" { diff --git a/internal/app/server/hash_handler.go b/internal/app/server/hash_handler.go index 74869c5..2ff6f4e 100644 --- a/internal/app/server/hash_handler.go +++ b/internal/app/server/hash_handler.go @@ -79,6 +79,7 @@ func (h hashHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request Hash: encodedHash, } + writer.Header().Set("Content-Type", "application/json") encoder := json.NewEncoder(writer) if err = encoder.Encode(resp); err != nil { writer.WriteHeader(500) diff --git a/internal/app/server/http_server.go b/internal/app/server/http_server.go index d5a4219..a3ff29c 100644 --- a/internal/app/server/http_server.go +++ b/internal/app/server/http_server.go @@ -5,11 +5,15 @@ import ( "net" "net/http" - "github.com/baez90/go-reveal-slides/internal/app/rendering" - "github.com/baez90/go-reveal-slides/internal/app/routing" + "github.com/baez90/goveal/internal/app/rendering" + "github.com/baez90/goveal/internal/app/routing" "github.com/markbates/pkger" ) +const ( + markdownFilePath = "/content.md" +) + type Config struct { Host string Port uint16 @@ -31,6 +35,9 @@ func (srv HTTPServer) ListenAddress() string { } func NewHTTPServer(config Config) (srv *HTTPServer, err error) { + + noCacheFiles := append(config.RevealParams.FilesToMonitor, markdownFilePath) + router := &routing.RegexpRouter{} var tmplRenderer rendering.RevealRenderer if tmplRenderer, err = rendering.NewRevealRenderer(config.RevealParams); err != nil { @@ -50,20 +57,20 @@ func NewHTTPServer(config Config) (srv *HTTPServer, err error) { fs := routing.NewLayeredFileSystem(pkger.Dir("/assets/reveal"), pkger.Dir("/assets/web"), http.Dir("."), mdFS) //language=regexp - if err = router.AddRule(`^(?i)/hash/(md5|sha1|sha2)/.*`, routing.NoCache(NewHashHandler(fs))); err != nil { + if err = router.AddRule(`^(?i)/hash/(md5|sha1|sha2)/.*`, NewHashHandler(fs)); err != nil { return } - if err = router.AddRule("^/.*\\.md$", routing.NoCache(http.FileServer(mdFS))); err != nil { + if err = router.AddRule("^/.*\\.md$", http.FileServer(mdFS)); err != nil { return } - if err = router.AddRule("/.+", routing.NoCache(http.FileServer(fs))); err != nil { + if err = router.AddRule("/.+", http.FileServer(fs)); err != nil { return } hostPort := fmt.Sprintf("%s:%d", config.Host, config.Port) srv = &HTTPServer{ - handler: router, + handler: routing.NoCache(router, noCacheFiles), } if srv.listener, err = net.Listen("tcp", hostPort); err != nil {