From 4d32f2fa8969f368b088dc9bcedb45f2c986cb27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Tue, 10 Apr 2018 09:19:26 +0200 Subject: [PATCH] commands: Make the hugo command non-global See #4598 --- commands/benchmark.go | 21 +-- commands/check.go | 10 +- commands/commandeer.go | 21 +-- commands/convert.go | 36 ++--- commands/env.go | 10 +- commands/gen.go | 10 +- commands/genautocomplete.go | 10 +- commands/genchromastyles.go | 10 +- commands/gendoc.go | 10 +- commands/gendocshelper.go | 10 +- commands/genman.go | 10 +- commands/helpers.go | 17 ++ commands/hugo.go | 307 +++++++++++++++++++----------------- commands/import_jekyll.go | 15 +- commands/limit_darwin.go | 8 +- commands/list.go | 20 ++- commands/list_config.go | 12 +- commands/new.go | 12 +- commands/new_site.go | 8 +- commands/new_theme.go | 10 +- commands/release.go | 3 +- commands/server.go | 55 +++---- commands/version.go | 10 +- 23 files changed, 299 insertions(+), 336 deletions(-) diff --git a/commands/benchmark.go b/commands/benchmark.go index ae5d436e..b1291cc4 100644 --- a/commands/benchmark.go +++ b/commands/benchmark.go @@ -23,22 +23,12 @@ import ( jww "github.com/spf13/jwalterweatherman" ) -var _ cmder = (*benchmarkCmd)(nil) - type benchmarkCmd struct { benchmarkTimes int cpuProfileFile string memProfileFile string - cmd *cobra.Command -} - -type cmder interface { - getCommand() *cobra.Command -} - -func (c *benchmarkCmd) getCommand() *cobra.Command { - return c.cmd + *baseBuilderCmd } func newBenchmarkCmd() *benchmarkCmd { @@ -49,15 +39,14 @@ func newBenchmarkCmd() *benchmarkCmd { creating a benchmark.`, } - initHugoBuilderFlags(cmd) - initBenchmarkBuildingFlags(cmd) - - c := &benchmarkCmd{cmd: cmd} + c := &benchmarkCmd{baseBuilderCmd: newBuilderCmd(cmd)} cmd.Flags().StringVar(&c.cpuProfileFile, "cpuprofile", "", "path/filename for the CPU profile file") cmd.Flags().StringVar(&c.memProfileFile, "memprofile", "", "path/filename for the memory profile file") cmd.Flags().IntVarP(&c.benchmarkTimes, "count", "n", 13, "number of times to build the site") + cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)") + cmd.RunE = c.benchmark return c @@ -67,7 +56,7 @@ func (c *benchmarkCmd) benchmark(cmd *cobra.Command, args []string) error { cfgInit := func(c *commandeer) error { return nil } - comm, err := InitializeConfig(false, cfgInit, c.cmd) + comm, err := initializeConfig(false, &c.hugoBuilderCommon, c, cfgInit) if err != nil { return err } diff --git a/commands/check.go b/commands/check.go index 5812bb6a..f20a18b0 100644 --- a/commands/check.go +++ b/commands/check.go @@ -20,17 +20,13 @@ import ( var _ cmder = (*checkCmd)(nil) type checkCmd struct { - cmd *cobra.Command + *baseCmd } func newCheckCmd() *checkCmd { - return &checkCmd{cmd: &cobra.Command{ + return &checkCmd{baseCmd: &baseCmd{cmd: &cobra.Command{ Use: "check", Short: "Contains some verification checks", }, - } -} - -func (c *checkCmd) getCommand() *cobra.Command { - return c.cmd + }} } diff --git a/commands/commandeer.go b/commands/commandeer.go index 7d053f24..4c8abd7d 100644 --- a/commands/commandeer.go +++ b/commands/commandeer.go @@ -40,7 +40,8 @@ import ( type commandeer struct { *deps.DepsCfg - subCmdVs []*cobra.Command + h *hugoBuilderCommon + ftch flagsToConfigHandler pathSpec *helpers.PathSpec visitedURLs *types.EvictingStringQueue @@ -96,7 +97,7 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error { return nil } -func newCommandeer(running bool, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) { +func newCommandeer(running bool, h *hugoBuilderCommon, f flagsToConfigHandler, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) { var rebuildDebouncer func(f func()) if running { @@ -107,8 +108,9 @@ func newCommandeer(running bool, doWithCommandeer func(c *commandeer) error, sub } c := &commandeer{ + h: h, + ftch: f, doWithCommandeer: doWithCommandeer, - subCmdVs: append([]*cobra.Command{hugoCmdV}, subCmdVs...), visitedURLs: types.NewEvictingStringQueue(10), debounce: rebuildDebouncer, } @@ -127,8 +129,8 @@ func (c *commandeer) loadConfig(running bool) error { cfg.Running = running var dir string - if source != "" { - dir, _ = filepath.Abs(source) + if c.h.source != "" { + dir, _ = filepath.Abs(c.h.source) } else { dir, _ = os.Getwd() } @@ -139,8 +141,9 @@ func (c *commandeer) loadConfig(running bool) error { } doWithConfig := func(cfg config.Provider) error { - for _, cmdV := range c.subCmdVs { - initializeFlags(cmdV, cfg) + + if c.ftch != nil { + c.ftch.flagsToConfig(cfg) } cfg.Set("workingDir", dir) @@ -158,7 +161,7 @@ func (c *commandeer) loadConfig(running bool) error { } config, configFiles, err := hugolib.LoadConfig( - hugolib.ConfigSourceDescriptor{Fs: sourceFs, Path: source, WorkingDir: dir, Filename: cfgFile}, + hugolib.ConfigSourceDescriptor{Fs: sourceFs, Path: c.h.source, WorkingDir: dir, Filename: c.h.cfgFile}, doWithCommandeer, doWithConfig) @@ -181,7 +184,7 @@ func (c *commandeer) loadConfig(running bool) error { } } - logger, err := createLogger(config) + logger, err := c.createLogger(config) if err != nil { return err } diff --git a/commands/convert.go b/commands/convert.go index cc07fe08..9e0a6602 100644 --- a/commands/convert.go +++ b/commands/convert.go @@ -32,31 +32,34 @@ var ( _ cmder = (*convertCmd)(nil) ) +// TODO(bep) cli refactor var outputDir string var unsafe bool type convertCmd struct { - cmd *cobra.Command + *baseBuilderCmd } func newConvertCmd() *convertCmd { - cmd := &cobra.Command{ + cc := &convertCmd{} + + cc.baseBuilderCmd = newBuilderCmd(&cobra.Command{ Use: "convert", Short: "Convert your content to different formats", Long: `Convert your content (e.g. front matter) to different formats. See convert's subcommands toJSON, toTOML and toYAML for more information.`, RunE: nil, - } + }) - cmd.AddCommand( + cc.cmd.AddCommand( &cobra.Command{ Use: "toJSON", Short: "Convert front matter to JSON", Long: `toJSON converts all front matter in the content directory to use JSON for the front matter.`, RunE: func(cmd *cobra.Command, args []string) error { - return convertContents(rune([]byte(parser.JSONLead)[0])) + return cc.convertContents(rune([]byte(parser.JSONLead)[0])) }, }, &cobra.Command{ @@ -65,7 +68,7 @@ to use JSON for the front matter.`, Long: `toTOML converts all front matter in the content directory to use TOML for the front matter.`, RunE: func(cmd *cobra.Command, args []string) error { - return convertContents(rune([]byte(parser.TOMLLead)[0])) + return cc.convertContents(rune([]byte(parser.TOMLLead)[0])) }, }, &cobra.Command{ @@ -74,29 +77,26 @@ to use TOML for the front matter.`, Long: `toYAML converts all front matter in the content directory to use YAML for the front matter.`, RunE: func(cmd *cobra.Command, args []string) error { - return convertContents(rune([]byte(parser.YAMLLead)[0])) + return cc.convertContents(rune([]byte(parser.YAMLLead)[0])) }, }, ) - cmd.PersistentFlags().StringVarP(&outputDir, "output", "o", "", "filesystem path to write files to") - cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") - cmd.PersistentFlags().BoolVar(&unsafe, "unsafe", false, "enable less safe operations, please backup first") - cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) + // TODO(bep) cli refactor + // cmd.PersistentFlags().StringVarP(&outputDir, "output", "o", "", "filesystem path to write files to") + // cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") + // cmd.PersistentFlags().BoolVar(&unsafe, "unsafe", false, "enable less safe operations, please backup first") + cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) - return &convertCmd{cmd: cmd} + return cc } -func (c *convertCmd) getCommand() *cobra.Command { - return c.cmd -} - -func convertContents(mark rune) error { +func (cc *convertCmd) convertContents(mark rune) error { if outputDir == "" && !unsafe { return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path") } - c, err := InitializeConfig(false, nil) + c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, nil) if err != nil { return err } diff --git a/commands/env.go b/commands/env.go index 700cddf5..76c16b93 100644 --- a/commands/env.go +++ b/commands/env.go @@ -23,15 +23,11 @@ import ( var _ cmder = (*envCmd)(nil) type envCmd struct { - cmd *cobra.Command -} - -func (c *envCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newEnvCmd() *envCmd { - return &envCmd{cmd: &cobra.Command{ + return &envCmd{baseCmd: newBaseCmd(&cobra.Command{ Use: "env", Short: "Print Hugo version and environment info", Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.`, @@ -43,6 +39,6 @@ func newEnvCmd() *envCmd { return nil }, - }, + }), } } diff --git a/commands/gen.go b/commands/gen.go index c22d8f8b..6878cfe7 100644 --- a/commands/gen.go +++ b/commands/gen.go @@ -20,19 +20,15 @@ import ( var _ cmder = (*genCmd)(nil) type genCmd struct { - cmd *cobra.Command -} - -func (c *genCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newGenCmd() *genCmd { cc := &genCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "gen", Short: "A collection of several useful generators.", - } + }) cc.cmd.AddCommand( newGenautocompleteCmd().getCommand(), diff --git a/commands/genautocomplete.go b/commands/genautocomplete.go index 24563545..b0b98abb 100644 --- a/commands/genautocomplete.go +++ b/commands/genautocomplete.go @@ -26,17 +26,13 @@ type genautocompleteCmd struct { // bash for now (zsh and others will come) autocompleteType string - cmd *cobra.Command -} - -func (c *genautocompleteCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newGenautocompleteCmd() *genautocompleteCmd { cc := &genautocompleteCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "autocomplete", Short: "Generate shell autocompletion script for Hugo", Long: `Generates a shell autocompletion script for Hugo. @@ -72,7 +68,7 @@ or just source them in directly: return nil }, - } + }) cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteTarget, "completionfile", "", "/etc/bash_completion.d/hugo.sh", "autocompletion file") cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteType, "type", "", "bash", "autocompletion type (currently only bash supported)") diff --git a/commands/genchromastyles.go b/commands/genchromastyles.go index 6d7b8b5c..a2231e56 100644 --- a/commands/genchromastyles.go +++ b/commands/genchromastyles.go @@ -30,23 +30,19 @@ type genChromaStyles struct { style string highlightStyle string linesStyle string - cmd *cobra.Command -} - -func (c *genChromaStyles) getCommand() *cobra.Command { - return c.cmd + *baseCmd } // TODO(bep) highlight func createGenChromaStyles() *genChromaStyles { g := &genChromaStyles{ - cmd: &cobra.Command{ + baseCmd: newBaseCmd(&cobra.Command{ Use: "chromastyles", Short: "Generate CSS stylesheet for the Chroma code highlighter", Long: `Generate CSS stylesheet for the Chroma code highlighter for a given style. This stylesheet is needed if pygmentsUseClasses is enabled in config. See https://help.farbox.com/pygments.html for preview of available styles`, - }, + }), } g.cmd.RunE = func(cmd *cobra.Command, args []string) error { diff --git a/commands/gendoc.go b/commands/gendoc.go index 8c46fe98..3446c262 100644 --- a/commands/gendoc.go +++ b/commands/gendoc.go @@ -31,11 +31,7 @@ var _ cmder = (*genDocCmd)(nil) type genDocCmd struct { gendocdir string - cmd *cobra.Command -} - -func (c *genDocCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newGenDocCmd() *genDocCmd { @@ -49,7 +45,7 @@ url: %s cc := &genDocCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "doc", Short: "Generate Markdown documentation for the Hugo CLI.", Long: `Generate Markdown documentation for the Hugo CLI. @@ -89,7 +85,7 @@ for rendering in Hugo.`, return nil }, - } + }) cc.cmd.PersistentFlags().StringVar(&cc.gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.") diff --git a/commands/gendocshelper.go b/commands/gendocshelper.go index e98bfde7..c243581f 100644 --- a/commands/gendocshelper.go +++ b/commands/gendocshelper.go @@ -29,20 +29,16 @@ var ( type genDocsHelper struct { target string - cmd *cobra.Command -} - -func (c *genDocsHelper) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func createGenDocsHelper() *genDocsHelper { g := &genDocsHelper{ - cmd: &cobra.Command{ + baseCmd: newBaseCmd(&cobra.Command{ Use: "docshelper", Short: "Generate some data files for the Hugo docs.", Hidden: true, - }, + }), } g.cmd.RunE = func(cmd *cobra.Command, args []string) error { diff --git a/commands/genman.go b/commands/genman.go index fd9a4972..ac4eaf8d 100644 --- a/commands/genman.go +++ b/commands/genman.go @@ -28,17 +28,13 @@ var _ cmder = (*genManCmd)(nil) type genManCmd struct { genmandir string - cmd *cobra.Command -} - -func (c *genManCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newGenManCmd() *genManCmd { cc := &genManCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "man", Short: "Generate man pages for the Hugo CLI", Long: `This command automatically generates up-to-date man pages of Hugo's @@ -69,7 +65,7 @@ in the "man" directory under the current directory.`, return nil }, - } + }) cc.cmd.PersistentFlags().StringVar(&cc.genmandir, "dir", "man/", "the directory to write the man pages.") diff --git a/commands/helpers.go b/commands/helpers.go index 78e549d2..1386e425 100644 --- a/commands/helpers.go +++ b/commands/helpers.go @@ -15,6 +15,14 @@ // used by Hugo. Commands and flags are implemented using Cobra. package commands +import ( + "fmt" + "regexp" + + "github.com/gohugoio/hugo/config" + "github.com/spf13/cobra" +) + const ( ansiEsc = "\u001B" clearLine = "\r\033[K" @@ -22,6 +30,15 @@ const ( showCursor = ansiEsc + "[?25h" ) +type flagsToConfigHandler interface { + flagsToConfig(cfg config.Provider) +} + +type cmder interface { + flagsToConfigHandler + getCommand() *cobra.Command +} + // commandError is an error used to signal different error situations in command handling. type commandError struct { s string diff --git a/commands/hugo.go b/commands/hugo.go index 3f468dd7..1da764d9 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -39,8 +39,6 @@ import ( "github.com/gohugoio/hugo/parser" flag "github.com/spf13/pflag" - "regexp" - "github.com/fsnotify/fsnotify" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/hugolib" @@ -54,137 +52,123 @@ import ( "github.com/spf13/nitro" ) -// Hugo represents the Hugo sites to build. This variable is exported as it -// is used by at least one external library (the Hugo caddy plugin). We should -// provide a cleaner external API, but until then, this is it. -var Hugo *hugolib.HugoSites - -// Reset resets Hugo ready for a new full build. This is mainly only useful -// for benchmark testing etc. via the CLI commands. -func Reset() error { - Hugo = nil - return nil +type baseCmd struct { + cmd *cobra.Command } -// HugoCmd is Hugo's root command. -// Every other command attached to HugoCmd is a child command to it. -var HugoCmd = &cobra.Command{ - Use: "hugo", - Short: "hugo builds your site", - Long: `hugo is the main command, used to build your Hugo site. +type baseBuilderCmd struct { + hugoBuilderCommon + *baseCmd +} + +func (c *baseCmd) getCommand() *cobra.Command { + return c.cmd +} + +func newBaseCmd(cmd *cobra.Command) *baseCmd { + return &baseCmd{cmd: cmd} +} + +func newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd { + bcmd := &baseBuilderCmd{baseCmd: &baseCmd{cmd: cmd}} + bcmd.hugoBuilderCommon.handleFlags(cmd) + return bcmd +} + +// TODO(bep) cli refactor need root? +func (c *baseCmd) flagsToConfig(cfg config.Provider) { + initializeFlags(c.cmd, cfg) +} + +type hugoCmd struct { + + //cacheDir string + //contentDir string + //layoutDir string + //destination string + //theme string + //themesDir string + //logI18nWarnings bool + //disableKinds []string + + *baseBuilderCmd +} + +func newHugoCmd() *hugoCmd { + cc := &hugoCmd{} + + cc.baseBuilderCmd = newBuilderCmd(&cobra.Command{ + Use: "hugo", + Short: "hugo builds your site", + Long: `hugo is the main command, used to build your Hugo site. Hugo is a Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://gohugo.io/.`, - RunE: func(cmd *cobra.Command, args []string) error { - - cfgInit := func(c *commandeer) error { - if buildWatch { - c.Set("disableLiveReload", true) + RunE: func(cmd *cobra.Command, args []string) error { + cfgInit := func(c *commandeer) error { + if cc.buildWatch { + c.Set("disableLiveReload", true) + } + return nil } - return nil - } - c, err := InitializeConfig(buildWatch, cfgInit) - if err != nil { - return err - } + c, err := initializeConfig(cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit) + if err != nil { + return err + } - return c.build() - }, + return c.build() + }, + }) + + cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)") + cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode") + + // Set bash-completion + validConfigFilenames := []string{"json", "js", "yaml", "yml", "toml", "tml"} + _ = cc.cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames) + + cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output") + cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output") + cc.cmd.PersistentFlags().BoolVar(&cc.logging, "log", false, "enable Logging") + cc.cmd.PersistentFlags().StringVar(&cc.logFile, "logFile", "", "log File path (if set, logging enabled automatically)") + cc.cmd.PersistentFlags().BoolVar(&cc.verboseLog, "verboseLog", false, "verbose logging") + + cc.cmd.Flags().BoolVarP(&cc.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed") + + // Set bash-completion + _ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{}) + + return cc } -var hugoCmdV *cobra.Command +type hugoBuilderCommon struct { + source string + baseURL string -type flagVals struct { -} - -// Flags that are to be added to commands. -var ( - // TODO(bep) var vs string buildWatch bool + + gc bool + + // TODO(bep) var vs string logging bool verbose bool verboseLog bool debug bool quiet bool -) -var ( - gc bool - baseURL string - //cacheDir string - //contentDir string - //layoutDir string cfgFile string - //destination string logFile string - //theme string - //themesDir string - source string - //logI18nWarnings bool - //disableKinds []string -) - -// Execute adds all child commands to the root command HugoCmd and sets flags appropriately. -func Execute() { - HugoCmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags) - - HugoCmd.SilenceUsage = true - - AddCommands() - - if c, err := HugoCmd.ExecuteC(); err != nil { - if isUserError(err) { - c.Println("") - c.Println(c.UsageString()) - } - - os.Exit(-1) - } } -// AddCommands adds child commands to the root command HugoCmd. -func AddCommands() { - HugoCmd.AddCommand(newServerCmd().getCommand()) - HugoCmd.AddCommand(newVersionCmd().getCommand()) - HugoCmd.AddCommand(newEnvCmd().getCommand()) - HugoCmd.AddCommand(newConfigCmd().getCommand()) - HugoCmd.AddCommand(newCheckCmd().getCommand()) - HugoCmd.AddCommand(newBenchmarkCmd().getCommand()) - HugoCmd.AddCommand(newConvertCmd().getCommand()) - HugoCmd.AddCommand(newNewCmd().getCommand()) - HugoCmd.AddCommand(newListCmd().getCommand()) - HugoCmd.AddCommand(newImportCmd().getCommand()) - - HugoCmd.AddCommand(newGenCmd().getCommand()) - -} - -// initHugoBuilderFlags initializes all common flags, typically used by the -// core build commands, namely hugo itself, server, check and benchmark. -func initHugoBuilderFlags(cmd *cobra.Command) { - initHugoBuildCommonFlags(cmd) -} - -func initRootPersistentFlags() { - HugoCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)") - HugoCmd.PersistentFlags().BoolVar(&quiet, "quiet", false, "build in quiet mode") - - // Set bash-completion - validConfigFilenames := []string{"json", "js", "yaml", "yml", "toml", "tml"} - _ = HugoCmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames) -} - -// initHugoBuildCommonFlags initialize common flags related to the Hugo build. -// Called by initHugoBuilderFlags. -func initHugoBuildCommonFlags(cmd *cobra.Command) { +func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) { cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories") cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft") cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future") cmd.Flags().BoolP("buildExpired", "E", false, "include expired content") - cmd.Flags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") + cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from") cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory") cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory") cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/") @@ -194,9 +178,9 @@ func initHugoBuildCommonFlags(cmd *cobra.Command) { cmd.Flags().StringP("themesDir", "", "", "filesystem path to themes directory") cmd.Flags().Bool("uglyURLs", false, "(deprecated) if true, use /filename.html instead of /filename/") cmd.Flags().Bool("canonifyURLs", false, "(deprecated) if true, all relative URLs will be canonicalized using baseURL") - cmd.Flags().StringVarP(&baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/") + cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/") cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages") - cmd.Flags().BoolVar(&gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build") + cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build") cmd.Flags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program") cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions") @@ -218,33 +202,74 @@ func initHugoBuildCommonFlags(cmd *cobra.Command) { _ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"}) } -func initBenchmarkBuildingFlags(cmd *cobra.Command) { - cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)") +// Hugo represents the Hugo sites to build. This variable is exported as it +// is used by at least one external library (the Hugo caddy plugin). We should +// provide a cleaner external API, but until then, this is it. +var Hugo *hugolib.HugoSites + +// Reset resets Hugo ready for a new full build. This is mainly only useful +// for benchmark testing etc. via the CLI commands. +func Reset() error { + Hugo = nil + return nil } -// init initializes flags. -func init() { - HugoCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output") - HugoCmd.PersistentFlags().BoolVarP(&debug, "debug", "", false, "debug output") - HugoCmd.PersistentFlags().BoolVar(&logging, "log", false, "enable Logging") - HugoCmd.PersistentFlags().StringVar(&logFile, "logFile", "", "log File path (if set, logging enabled automatically)") - HugoCmd.PersistentFlags().BoolVar(&verboseLog, "verboseLog", false, "verbose logging") +var ( + hugoCommand = newHugoCmd() - initRootPersistentFlags() - initHugoBuilderFlags(HugoCmd) - initBenchmarkBuildingFlags(HugoCmd) + // HugoCmd is Hugo's root command. + // Every other command attached to HugoCmd is a child command to it. + HugoCmd = hugoCommand.getCommand() +) - HugoCmd.Flags().BoolVarP(&buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed") - hugoCmdV = HugoCmd +// Execute adds all child commands to the root command HugoCmd and sets flags appropriately. +func Execute() { + HugoCmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags) - // Set bash-completion - _ = HugoCmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{}) + HugoCmd.SilenceUsage = true + + addAllCommands() + + if c, err := HugoCmd.ExecuteC(); err != nil { + if isUserError(err) { + c.Println("") + c.Println(c.UsageString()) + } + + os.Exit(-1) + } +} + +// addAllCommands adds child commands to the root command HugoCmd. +func addAllCommands() { + addCommands( + newServerCmd(), + newVersionCmd(), + newEnvCmd(), + newConfigCmd(), + newCheckCmd(), + newBenchmarkCmd(), + newConvertCmd(), + newNewCmd(), + newListCmd(), + newImportCmd(), + newGenCmd(), + ) +} + +func addCommands(commands ...cmder) { + for _, command := range commands { + HugoCmd.AddCommand(command.getCommand()) + } } // InitializeConfig initializes a config file with sensible default configuration flags. -func InitializeConfig(running bool, doWithCommandeer func(c *commandeer) error, subCmdVs ...*cobra.Command) (*commandeer, error) { +func initializeConfig(running bool, + h *hugoBuilderCommon, + f flagsToConfigHandler, + doWithCommandeer func(c *commandeer) error) (*commandeer, error) { - c, err := newCommandeer(running, doWithCommandeer, subCmdVs...) + c, err := newCommandeer(running, h, f, doWithCommandeer) if err != nil { return nil, err } @@ -253,7 +278,7 @@ func InitializeConfig(running bool, doWithCommandeer func(c *commandeer) error, } -func createLogger(cfg config.Provider) (*jww.Notepad, error) { +func (c *commandeer) createLogger(cfg config.Provider) (*jww.Notepad, error) { var ( logHandle = ioutil.Discard logThreshold = jww.LevelWarn @@ -262,7 +287,7 @@ func createLogger(cfg config.Provider) (*jww.Notepad, error) { stdoutThreshold = jww.LevelError ) - if verboseLog || logging || (logFile != "") { + if c.h.verboseLog || c.h.logging || (c.h.logFile != "") { var err error if logFile != "" { logHandle, err = os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) @@ -275,7 +300,7 @@ func createLogger(cfg config.Provider) (*jww.Notepad, error) { return nil, newSystemError(err) } } - } else if !quiet && cfg.GetBool("verbose") { + } else if !c.h.quiet && cfg.GetBool("verbose") { stdoutThreshold = jww.LevelInfo } @@ -283,7 +308,7 @@ func createLogger(cfg config.Provider) (*jww.Notepad, error) { stdoutThreshold = jww.LevelDebug } - if verboseLog { + if c.h.verboseLog { logThreshold = jww.LevelInfo if cfg.GetBool("debug") { logThreshold = jww.LevelDebug @@ -381,7 +406,7 @@ func (c *commandeer) fullBuild() error { langCount map[string]uint64 ) - if !quiet { + if !c.h.quiet { fmt.Print(hideCursor + "Building sites … ") defer func() { fmt.Print(showCursor + clearLine) @@ -424,7 +449,7 @@ func (c *commandeer) fullBuild() error { s.ProcessingStats.Static = langCount[s.Language.Lang] } - if gc { + if c.h.gc { count, err := Hugo.GC() if err != nil { return err @@ -447,13 +472,13 @@ func (c *commandeer) build() error { } // TODO(bep) Feedback? - if !quiet { + if !c.h.quiet { fmt.Println() Hugo.PrintProcessingStats(os.Stdout) fmt.Println() } - if buildWatch { + if c.h.buildWatch { watchDirs, err := c.getDirList() if err != nil { return err @@ -481,7 +506,7 @@ func (c *commandeer) serverBuild() error { } // TODO(bep) Feedback? - if !quiet { + if !c.h.quiet { fmt.Println() Hugo.PrintProcessingStats(os.Stdout) fmt.Println() @@ -613,7 +638,7 @@ func (c *commandeer) copyStaticTo(dirs *src.Dirs, publishDir string) (uint64, er } func (c *commandeer) timeTrack(start time.Time, name string) { - if quiet { + if c.h.quiet { return } elapsed := time.Since(start) @@ -765,7 +790,7 @@ func (c *commandeer) recreateAndBuildSites(watching bool) (err error) { if err := c.initSites(); err != nil { return err } - if !quiet { + if !c.h.quiet { c.Logger.FEEDBACK.Println("Started building sites ...") } return Hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true}) @@ -775,7 +800,7 @@ func (c *commandeer) resetAndBuildSites() (err error) { if err = c.initSites(); err != nil { return } - if !quiet { + if !c.h.quiet { c.Logger.FEEDBACK.Println("Started building sites ...") } return Hugo.Build(hugolib.BuildCfg{ResetState: true}) @@ -811,7 +836,7 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error { return err } visited := c.visitedURLs.PeekAllSet() - doLiveReload := !buildWatch && !c.Cfg.GetBool("disableLiveReload") + doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") if doLiveReload && !c.Cfg.GetBool("disableFastRender") { // Make sure we always render the home pages @@ -833,7 +858,7 @@ func (c *commandeer) fullRebuild() { jww.ERROR.Println("Failed to reload config:", err) } else if err := c.recreateAndBuildSites(true); err != nil { jww.ERROR.Println(err) - } else if !buildWatch && !c.Cfg.GetBool("disableLiveReload") { + } else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") { livereload.ForceRefresh() } } @@ -1013,7 +1038,7 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) { } } - if !buildWatch && !c.Cfg.GetBool("disableLiveReload") { + if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") { // Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized // force refresh when more than one file @@ -1030,7 +1055,7 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) { } if len(dynamicEvents) > 0 { - doLiveReload := !buildWatch && !c.Cfg.GetBool("disableLiveReload") + doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") onePageName := pickOneWriteOrCreatePath(dynamicEvents) c.Logger.FEEDBACK.Println("\nChange detected, rebuilding site") diff --git a/commands/import_jekyll.go b/commands/import_jekyll.go index df36951c..af8a5acb 100644 --- a/commands/import_jekyll.go +++ b/commands/import_jekyll.go @@ -35,27 +35,23 @@ import ( jww "github.com/spf13/jwalterweatherman" ) -var _ cmder = (*newThemeCmd)(nil) +var _ cmder = (*importCmd)(nil) type importCmd struct { - cmd *cobra.Command -} - -func (c *importCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newImportCmd() *importCmd { cc := &importCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "import", Short: "Import your site from others.", Long: `Import your site from other web site generators like Jekyll. Import requires a subcommand, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.", RunE: nil, - } + }) importJekyllCmd := &cobra.Command{ Use: "jekyll", @@ -74,9 +70,6 @@ Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root } -func init() { -} - func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error { if len(args) < 2 { diff --git a/commands/limit_darwin.go b/commands/limit_darwin.go index bc5f42a5..20341fa1 100644 --- a/commands/limit_darwin.go +++ b/commands/limit_darwin.go @@ -23,7 +23,7 @@ import ( var _ cmder = (*limitCmd)(nil) type limitCmd struct { - cmd *cobra.Command + *baseCmd } func newLimitCmd() *limitCmd { @@ -58,11 +58,7 @@ This is primarily to ensure that Hugo can watch enough files on some OSs`, }, } - return &limitCmd{cmd: ccmd} -} - -func (c *limitCmd) getCommand() *cobra.Command { - return c.cmd + return &limitCmd{baseCmd: newBaseCmd(ccmd)} } func init() { diff --git a/commands/list.go b/commands/list.go index c21158f6..49024be9 100644 --- a/commands/list.go +++ b/commands/list.go @@ -24,24 +24,21 @@ import ( var _ cmder = (*listCmd)(nil) type listCmd struct { - cmd *cobra.Command -} - -func (c *listCmd) getCommand() *cobra.Command { - return c.cmd + hugoBuilderCommon + *baseCmd } func newListCmd() *listCmd { cc := &listCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "list", Short: "Listing out various types of content", Long: `Listing out various types of content. List requires a subcommand, e.g. ` + "`hugo list drafts`.", RunE: nil, - } + }) cc.cmd.AddCommand( &cobra.Command{ @@ -53,7 +50,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.", c.Set("buildDrafts", true) return nil } - c, err := InitializeConfig(false, cfgInit) + c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit) if err != nil { return err } @@ -89,7 +86,7 @@ posted in the future.`, c.Set("buildFuture", true) return nil } - c, err := InitializeConfig(false, cfgInit) + c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit) if err != nil { return err } @@ -125,7 +122,7 @@ expired.`, c.Set("buildExpired", true) return nil } - c, err := InitializeConfig(false, cfgInit) + c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit) if err != nil { return err } @@ -153,7 +150,8 @@ expired.`, }, ) - cc.cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") + // TODO(bep) cli refactor + // cc.cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) return cc diff --git a/commands/list_config.go b/commands/list_config.go index b0399159..32b739d8 100644 --- a/commands/list_config.go +++ b/commands/list_config.go @@ -25,27 +25,23 @@ import ( var _ cmder = (*configCmd)(nil) type configCmd struct { - cmd *cobra.Command -} - -func (c *configCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newConfigCmd() *configCmd { cc := &configCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "config", Short: "Print the site configuration", Long: `Print the site configuration, both default and custom settings.`, RunE: cc.printConfig, - } + }) return cc } func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error { - cfg, err := InitializeConfig(false, nil, c.cmd) + cfg, err := initializeConfig(false, nil, c, nil) if err != nil { return err diff --git a/commands/new.go b/commands/new.go index f4caff50..2fb35a9a 100644 --- a/commands/new.go +++ b/commands/new.go @@ -33,15 +33,11 @@ type newCmd struct { contentEditor string contentType string - cmd *cobra.Command -} - -func (c *newCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newNewCmd() *newCmd { - ccmd := &newCmd{} + ccmd := &newCmd{baseCmd: newBaseCmd(nil)} cmd := &cobra.Command{ Use: "new [path]", Short: "Create new content for your site", @@ -57,7 +53,7 @@ If archetypes are provided in your theme or site, they will be used.`, cmd.Flags().StringVarP(&ccmd.contentType, "kind", "k", "", "content type to create") // TODO(bep) cli refactor - cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") + // cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) cmd.Flags().StringVar(&ccmd.contentEditor, "editor", "", "edit new content with this editor, if provided") @@ -77,7 +73,7 @@ func (n *newCmd) newContent(cmd *cobra.Command, args []string) error { return nil } - c, err := InitializeConfig(false, cfgInit) + c, err := initializeConfig(false, nil, n, cfgInit) if err != nil { return err diff --git a/commands/new_site.go b/commands/new_site.go index bad74682..4e3aab1d 100644 --- a/commands/new_site.go +++ b/commands/new_site.go @@ -40,11 +40,7 @@ var _ cmder = (*newSiteCmd)(nil) type newSiteCmd struct { configFormat string - cmd *cobra.Command -} - -func (c *newSiteCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newNewSiteCmd() *newSiteCmd { @@ -62,7 +58,7 @@ Use ` + "`hugo new [contentPath]`" + ` to create new content.`, cmd.Flags().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format") cmd.Flags().Bool("force", false, "init inside non-empty directory") - ccmd.cmd = cmd + ccmd.baseCmd = newBaseCmd(cmd) return ccmd diff --git a/commands/new_theme.go b/commands/new_theme.go index 4ff239f2..64220a8f 100644 --- a/commands/new_theme.go +++ b/commands/new_theme.go @@ -31,15 +31,11 @@ import ( var _ cmder = (*newThemeCmd)(nil) type newThemeCmd struct { - cmd *cobra.Command -} - -func (c *newThemeCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newNewThemeCmd() *newThemeCmd { - ccmd := &newThemeCmd{} + ccmd := &newThemeCmd{newBaseCmd(nil)} cmd := &cobra.Command{ Use: "theme [name]", @@ -57,7 +53,7 @@ as you see fit.`, } func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error { - c, err := InitializeConfig(false, nil) + c, err := initializeConfig(false, nil, n, nil) if err != nil { return err diff --git a/commands/release.go b/commands/release.go index 8ccf8bcc..1846be00 100644 --- a/commands/release.go +++ b/commands/release.go @@ -23,7 +23,8 @@ import ( ) func init() { - HugoCmd.AddCommand(createReleaser().cmd) + // TODO(bep) cli refactor + //HugoCmd.AddCommand(createReleaser().cmd) } type releaseCommandeer struct { diff --git a/commands/server.go b/commands/server.go index ce03eacb..7db963e4 100644 --- a/commands/server.go +++ b/commands/server.go @@ -38,9 +38,9 @@ import ( jww "github.com/spf13/jwalterweatherman" ) -var _ cmder = (*serverCmd)(nil) - type serverCmd struct { + hugoBuilderCommon + disableLiveReload bool navigateToChanged bool renderToDisk bool @@ -53,17 +53,31 @@ type serverCmd struct { disableFastRender bool - cmd *cobra.Command + *baseCmd } -func (c *serverCmd) getCommand() *cobra.Command { - return c.cmd +func (cc *serverCmd) handleFlags(cmd *cobra.Command) { + // TODO(bep) cli refactor fields vs strings + cc.cmd.Flags().IntVarP(&cc.serverPort, "port", "p", 1313, "port on which the server will listen") + cc.cmd.Flags().IntVar(&cc.liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)") + cc.cmd.Flags().StringVarP(&cc.serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind") + cc.cmd.Flags().BoolVarP(&cc.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed") + cc.cmd.Flags().BoolVar(&cc.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching") + cc.cmd.Flags().BoolVarP(&cc.serverAppend, "appendPort", "", true, "append port to baseURL") + cc.cmd.Flags().BoolVar(&cc.disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild") + cc.cmd.Flags().BoolVar(&cc.navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload") + cc.cmd.Flags().BoolVar(&cc.renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)") + cc.cmd.Flags().BoolVar(&cc.disableFastRender, "disableFastRender", false, "enables full re-renders on changes") + + cc.cmd.Flags().String("memstats", "", "log memory usage to this file") + cc.cmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + } func newServerCmd() *serverCmd { cc := &serverCmd{} - cc.cmd = &cobra.Command{ + cc.baseCmd = newBaseCmd(&cobra.Command{ Use: "server", Aliases: []string{"serve"}, Short: "A high performance webserver", @@ -80,24 +94,7 @@ automatically rebuild the site. It will then live reload any open browser pages and push the latest content to them. As most Hugo sites are built in a fraction of a second, you will be able to save and see your changes nearly instantly.`, RunE: cc.server, - } - - initHugoBuilderFlags(cc.cmd) - - // TODO(bep) cli refactor fields vs strings - cc.cmd.Flags().IntVarP(&cc.serverPort, "port", "p", 1313, "port on which the server will listen") - cc.cmd.Flags().IntVar(&cc.liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)") - cc.cmd.Flags().StringVarP(&cc.serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind") - cc.cmd.Flags().BoolVarP(&cc.serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed") - cc.cmd.Flags().BoolVar(&cc.noHTTPCache, "noHTTPCache", false, "prevent HTTP caching") - cc.cmd.Flags().BoolVarP(&cc.serverAppend, "appendPort", "", true, "append port to baseURL") - cc.cmd.Flags().BoolVar(&cc.disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild") - cc.cmd.Flags().BoolVar(&cc.navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload") - cc.cmd.Flags().BoolVar(&cc.renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)") - cc.cmd.Flags().BoolVar(&cc.disableFastRender, "disableFastRender", false, "enables full re-renders on changes") - - cc.cmd.Flags().String("memstats", "", "log memory usage to this file") - cc.cmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") + }) return cc } @@ -122,10 +119,6 @@ func (f noDirFile) Readdir(count int) ([]os.FileInfo, error) { return nil, nil } -func init() { - -} - var serverPorts []int func (s *serverCmd) server(cmd *cobra.Command, args []string) error { @@ -212,7 +205,7 @@ func (s *serverCmd) server(cmd *cobra.Command, args []string) error { serverPort = serverPorts[0] } - baseURL, err := s.fixURL(language, baseURL, serverPort) + baseURL, err := s.fixURL(language, s.baseURL, serverPort) if err != nil { return nil } @@ -232,7 +225,7 @@ func (s *serverCmd) server(cmd *cobra.Command, args []string) error { jww.ERROR.Println("memstats error:", err) } - c, err := InitializeConfig(true, cfgInit, s.cmd) + c, err := initializeConfig(true, &s.hugoBuilderCommon, s, cfgInit) // TODO(bep) cli refactor if err != nil { return err @@ -308,7 +301,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro httpFs := afero.NewHttpFs(f.c.Fs.Destination) fs := filesOnlyFs{httpFs.Dir(absPublishDir)} - doLiveReload := !buildWatch && !f.c.Cfg.GetBool("disableLiveReload") + doLiveReload := !f.s.buildWatch && !f.c.Cfg.GetBool("disableLiveReload") fastRenderMode := doLiveReload && !f.c.Cfg.GetBool("disableFastRender") if i == 0 && fastRenderMode { diff --git a/commands/version.go b/commands/version.go index 4498c361..71ffd625 100644 --- a/commands/version.go +++ b/commands/version.go @@ -26,16 +26,12 @@ import ( var _ cmder = (*versionCmd)(nil) type versionCmd struct { - cmd *cobra.Command -} - -func (c *versionCmd) getCommand() *cobra.Command { - return c.cmd + *baseCmd } func newVersionCmd() *versionCmd { return &versionCmd{ - &cobra.Command{ + newBaseCmd(&cobra.Command{ Use: "version", Short: "Print the version number of Hugo", Long: `All software has versions. This is Hugo's.`, @@ -43,7 +39,7 @@ func newVersionCmd() *versionCmd { printHugoVersion() return nil }, - }, + }), } }