commands: Make the hugo command non-global

See #4598
This commit is contained in:
Bjørn Erik Pedersen 2018-04-10 09:19:26 +02:00
parent 018602c46d
commit 4d32f2fa89
No known key found for this signature in database
GPG key ID: 330E6E2BD4859D8F
23 changed files with 299 additions and 336 deletions

View file

@ -23,22 +23,12 @@ import (
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
) )
var _ cmder = (*benchmarkCmd)(nil)
type benchmarkCmd struct { type benchmarkCmd struct {
benchmarkTimes int benchmarkTimes int
cpuProfileFile string cpuProfileFile string
memProfileFile string memProfileFile string
cmd *cobra.Command *baseBuilderCmd
}
type cmder interface {
getCommand() *cobra.Command
}
func (c *benchmarkCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newBenchmarkCmd() *benchmarkCmd { func newBenchmarkCmd() *benchmarkCmd {
@ -49,15 +39,14 @@ func newBenchmarkCmd() *benchmarkCmd {
creating a benchmark.`, creating a benchmark.`,
} }
initHugoBuilderFlags(cmd) c := &benchmarkCmd{baseBuilderCmd: newBuilderCmd(cmd)}
initBenchmarkBuildingFlags(cmd)
c := &benchmarkCmd{cmd: cmd}
cmd.Flags().StringVar(&c.cpuProfileFile, "cpuprofile", "", "path/filename for the CPU profile file") 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().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().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 cmd.RunE = c.benchmark
return c return c
@ -67,7 +56,7 @@ func (c *benchmarkCmd) benchmark(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error { cfgInit := func(c *commandeer) error {
return nil return nil
} }
comm, err := InitializeConfig(false, cfgInit, c.cmd) comm, err := initializeConfig(false, &c.hugoBuilderCommon, c, cfgInit)
if err != nil { if err != nil {
return err return err
} }

View file

@ -20,17 +20,13 @@ import (
var _ cmder = (*checkCmd)(nil) var _ cmder = (*checkCmd)(nil)
type checkCmd struct { type checkCmd struct {
cmd *cobra.Command *baseCmd
} }
func newCheckCmd() *checkCmd { func newCheckCmd() *checkCmd {
return &checkCmd{cmd: &cobra.Command{ return &checkCmd{baseCmd: &baseCmd{cmd: &cobra.Command{
Use: "check", Use: "check",
Short: "Contains some verification checks", Short: "Contains some verification checks",
}, },
} }}
}
func (c *checkCmd) getCommand() *cobra.Command {
return c.cmd
} }

View file

@ -40,7 +40,8 @@ import (
type commandeer struct { type commandeer struct {
*deps.DepsCfg *deps.DepsCfg
subCmdVs []*cobra.Command h *hugoBuilderCommon
ftch flagsToConfigHandler
pathSpec *helpers.PathSpec pathSpec *helpers.PathSpec
visitedURLs *types.EvictingStringQueue visitedURLs *types.EvictingStringQueue
@ -96,7 +97,7 @@ func (c *commandeer) initFs(fs *hugofs.Fs) error {
return nil 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()) var rebuildDebouncer func(f func())
if running { if running {
@ -107,8 +108,9 @@ func newCommandeer(running bool, doWithCommandeer func(c *commandeer) error, sub
} }
c := &commandeer{ c := &commandeer{
h: h,
ftch: f,
doWithCommandeer: doWithCommandeer, doWithCommandeer: doWithCommandeer,
subCmdVs: append([]*cobra.Command{hugoCmdV}, subCmdVs...),
visitedURLs: types.NewEvictingStringQueue(10), visitedURLs: types.NewEvictingStringQueue(10),
debounce: rebuildDebouncer, debounce: rebuildDebouncer,
} }
@ -127,8 +129,8 @@ func (c *commandeer) loadConfig(running bool) error {
cfg.Running = running cfg.Running = running
var dir string var dir string
if source != "" { if c.h.source != "" {
dir, _ = filepath.Abs(source) dir, _ = filepath.Abs(c.h.source)
} else { } else {
dir, _ = os.Getwd() dir, _ = os.Getwd()
} }
@ -139,8 +141,9 @@ func (c *commandeer) loadConfig(running bool) error {
} }
doWithConfig := func(cfg config.Provider) 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) cfg.Set("workingDir", dir)
@ -158,7 +161,7 @@ func (c *commandeer) loadConfig(running bool) error {
} }
config, configFiles, err := hugolib.LoadConfig( 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, doWithCommandeer,
doWithConfig) doWithConfig)
@ -181,7 +184,7 @@ func (c *commandeer) loadConfig(running bool) error {
} }
} }
logger, err := createLogger(config) logger, err := c.createLogger(config)
if err != nil { if err != nil {
return err return err
} }

View file

@ -32,31 +32,34 @@ var (
_ cmder = (*convertCmd)(nil) _ cmder = (*convertCmd)(nil)
) )
// TODO(bep) cli refactor
var outputDir string var outputDir string
var unsafe bool var unsafe bool
type convertCmd struct { type convertCmd struct {
cmd *cobra.Command *baseBuilderCmd
} }
func newConvertCmd() *convertCmd { func newConvertCmd() *convertCmd {
cmd := &cobra.Command{ cc := &convertCmd{}
cc.baseBuilderCmd = newBuilderCmd(&cobra.Command{
Use: "convert", Use: "convert",
Short: "Convert your content to different formats", Short: "Convert your content to different formats",
Long: `Convert your content (e.g. front matter) 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.`, See convert's subcommands toJSON, toTOML and toYAML for more information.`,
RunE: nil, RunE: nil,
} })
cmd.AddCommand( cc.cmd.AddCommand(
&cobra.Command{ &cobra.Command{
Use: "toJSON", Use: "toJSON",
Short: "Convert front matter to JSON", Short: "Convert front matter to JSON",
Long: `toJSON converts all front matter in the content directory Long: `toJSON converts all front matter in the content directory
to use JSON for the front matter.`, to use JSON for the front matter.`,
RunE: func(cmd *cobra.Command, args []string) error { 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{ &cobra.Command{
@ -65,7 +68,7 @@ to use JSON for the front matter.`,
Long: `toTOML converts all front matter in the content directory Long: `toTOML converts all front matter in the content directory
to use TOML for the front matter.`, to use TOML for the front matter.`,
RunE: func(cmd *cobra.Command, args []string) error { 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{ &cobra.Command{
@ -74,29 +77,26 @@ to use TOML for the front matter.`,
Long: `toYAML converts all front matter in the content directory Long: `toYAML converts all front matter in the content directory
to use YAML for the front matter.`, to use YAML for the front matter.`,
RunE: func(cmd *cobra.Command, args []string) error { 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") // TODO(bep) cli refactor
cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from") // cmd.PersistentFlags().StringVarP(&outputDir, "output", "o", "", "filesystem path to write files to")
cmd.PersistentFlags().BoolVar(&unsafe, "unsafe", false, "enable less safe operations, please backup first") // cmd.PersistentFlags().StringVarP(&source, "source", "s", "", "filesystem path to read files relative from")
cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) // 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 { func (cc *convertCmd) convertContents(mark rune) error {
return c.cmd
}
func convertContents(mark rune) error {
if outputDir == "" && !unsafe { if outputDir == "" && !unsafe {
return newUserError("Unsafe operation not allowed, use --unsafe or set a different output path") 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 { if err != nil {
return err return err
} }

View file

@ -23,15 +23,11 @@ import (
var _ cmder = (*envCmd)(nil) var _ cmder = (*envCmd)(nil)
type envCmd struct { type envCmd struct {
cmd *cobra.Command *baseCmd
}
func (c *envCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newEnvCmd() *envCmd { func newEnvCmd() *envCmd {
return &envCmd{cmd: &cobra.Command{ return &envCmd{baseCmd: newBaseCmd(&cobra.Command{
Use: "env", Use: "env",
Short: "Print Hugo version and environment info", Short: "Print Hugo version and environment info",
Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.`, Long: `Print Hugo version and environment info. This is useful in Hugo bug reports.`,
@ -43,6 +39,6 @@ func newEnvCmd() *envCmd {
return nil return nil
}, },
}, }),
} }
} }

View file

@ -20,19 +20,15 @@ import (
var _ cmder = (*genCmd)(nil) var _ cmder = (*genCmd)(nil)
type genCmd struct { type genCmd struct {
cmd *cobra.Command *baseCmd
}
func (c *genCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newGenCmd() *genCmd { func newGenCmd() *genCmd {
cc := &genCmd{} cc := &genCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "gen", Use: "gen",
Short: "A collection of several useful generators.", Short: "A collection of several useful generators.",
} })
cc.cmd.AddCommand( cc.cmd.AddCommand(
newGenautocompleteCmd().getCommand(), newGenautocompleteCmd().getCommand(),

View file

@ -26,17 +26,13 @@ type genautocompleteCmd struct {
// bash for now (zsh and others will come) // bash for now (zsh and others will come)
autocompleteType string autocompleteType string
cmd *cobra.Command *baseCmd
}
func (c *genautocompleteCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newGenautocompleteCmd() *genautocompleteCmd { func newGenautocompleteCmd() *genautocompleteCmd {
cc := &genautocompleteCmd{} cc := &genautocompleteCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "autocomplete", Use: "autocomplete",
Short: "Generate shell autocompletion script for Hugo", Short: "Generate shell autocompletion script for Hugo",
Long: `Generates a 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 return nil
}, },
} })
cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteTarget, "completionfile", "", "/etc/bash_completion.d/hugo.sh", "autocompletion file") 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)") cc.cmd.PersistentFlags().StringVarP(&cc.autocompleteType, "type", "", "bash", "autocompletion type (currently only bash supported)")

View file

@ -30,23 +30,19 @@ type genChromaStyles struct {
style string style string
highlightStyle string highlightStyle string
linesStyle string linesStyle string
cmd *cobra.Command *baseCmd
}
func (c *genChromaStyles) getCommand() *cobra.Command {
return c.cmd
} }
// TODO(bep) highlight // TODO(bep) highlight
func createGenChromaStyles() *genChromaStyles { func createGenChromaStyles() *genChromaStyles {
g := &genChromaStyles{ g := &genChromaStyles{
cmd: &cobra.Command{ baseCmd: newBaseCmd(&cobra.Command{
Use: "chromastyles", Use: "chromastyles",
Short: "Generate CSS stylesheet for the Chroma code highlighter", 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. 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`, See https://help.farbox.com/pygments.html for preview of available styles`,
}, }),
} }
g.cmd.RunE = func(cmd *cobra.Command, args []string) error { g.cmd.RunE = func(cmd *cobra.Command, args []string) error {

View file

@ -31,11 +31,7 @@ var _ cmder = (*genDocCmd)(nil)
type genDocCmd struct { type genDocCmd struct {
gendocdir string gendocdir string
cmd *cobra.Command *baseCmd
}
func (c *genDocCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newGenDocCmd() *genDocCmd { func newGenDocCmd() *genDocCmd {
@ -49,7 +45,7 @@ url: %s
cc := &genDocCmd{} cc := &genDocCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "doc", Use: "doc",
Short: "Generate Markdown documentation for the Hugo CLI.", Short: "Generate Markdown documentation for the Hugo CLI.",
Long: `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 return nil
}, },
} })
cc.cmd.PersistentFlags().StringVar(&cc.gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.") cc.cmd.PersistentFlags().StringVar(&cc.gendocdir, "dir", "/tmp/hugodoc/", "the directory to write the doc.")

View file

@ -29,20 +29,16 @@ var (
type genDocsHelper struct { type genDocsHelper struct {
target string target string
cmd *cobra.Command *baseCmd
}
func (c *genDocsHelper) getCommand() *cobra.Command {
return c.cmd
} }
func createGenDocsHelper() *genDocsHelper { func createGenDocsHelper() *genDocsHelper {
g := &genDocsHelper{ g := &genDocsHelper{
cmd: &cobra.Command{ baseCmd: newBaseCmd(&cobra.Command{
Use: "docshelper", Use: "docshelper",
Short: "Generate some data files for the Hugo docs.", Short: "Generate some data files for the Hugo docs.",
Hidden: true, Hidden: true,
}, }),
} }
g.cmd.RunE = func(cmd *cobra.Command, args []string) error { g.cmd.RunE = func(cmd *cobra.Command, args []string) error {

View file

@ -28,17 +28,13 @@ var _ cmder = (*genManCmd)(nil)
type genManCmd struct { type genManCmd struct {
genmandir string genmandir string
cmd *cobra.Command *baseCmd
}
func (c *genManCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newGenManCmd() *genManCmd { func newGenManCmd() *genManCmd {
cc := &genManCmd{} cc := &genManCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "man", Use: "man",
Short: "Generate man pages for the Hugo CLI", Short: "Generate man pages for the Hugo CLI",
Long: `This command automatically generates up-to-date man pages of Hugo's 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 return nil
}, },
} })
cc.cmd.PersistentFlags().StringVar(&cc.genmandir, "dir", "man/", "the directory to write the man pages.") cc.cmd.PersistentFlags().StringVar(&cc.genmandir, "dir", "man/", "the directory to write the man pages.")

View file

@ -15,6 +15,14 @@
// used by Hugo. Commands and flags are implemented using Cobra. // used by Hugo. Commands and flags are implemented using Cobra.
package commands package commands
import (
"fmt"
"regexp"
"github.com/gohugoio/hugo/config"
"github.com/spf13/cobra"
)
const ( const (
ansiEsc = "\u001B" ansiEsc = "\u001B"
clearLine = "\r\033[K" clearLine = "\r\033[K"
@ -22,6 +30,15 @@ const (
showCursor = ansiEsc + "[?25h" 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. // commandError is an error used to signal different error situations in command handling.
type commandError struct { type commandError struct {
s string s string

View file

@ -39,8 +39,6 @@ import (
"github.com/gohugoio/hugo/parser" "github.com/gohugoio/hugo/parser"
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
"regexp"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
@ -54,21 +52,52 @@ import (
"github.com/spf13/nitro" "github.com/spf13/nitro"
) )
// Hugo represents the Hugo sites to build. This variable is exported as it type baseCmd struct {
// is used by at least one external library (the Hugo caddy plugin). We should cmd *cobra.Command
// 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
} }
// HugoCmd is Hugo's root command. type baseBuilderCmd struct {
// Every other command attached to HugoCmd is a child command to it. hugoBuilderCommon
var HugoCmd = &cobra.Command{ *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", Use: "hugo",
Short: "hugo builds your site", Short: "hugo builds your site",
Long: `hugo is the main command, used to build your Hugo site. Long: `hugo is the main command, used to build your Hugo site.
@ -78,113 +107,68 @@ built with love by spf13 and friends in Go.
Complete documentation is available at http://gohugo.io/.`, Complete documentation is available at http://gohugo.io/.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error { cfgInit := func(c *commandeer) error {
if buildWatch { if cc.buildWatch {
c.Set("disableLiveReload", true) c.Set("disableLiveReload", true)
} }
return nil return nil
} }
c, err := InitializeConfig(buildWatch, cfgInit) c, err := initializeConfig(cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil { if err != nil {
return err 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 buildWatch bool
gc bool
// TODO(bep) var vs string
logging bool logging bool
verbose bool verbose bool
verboseLog bool verboseLog bool
debug bool debug bool
quiet bool quiet bool
)
var (
gc bool
baseURL string
//cacheDir string
//contentDir string
//layoutDir string
cfgFile string cfgFile string
//destination string
logFile 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) func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
}
}
// 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) {
cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories") 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("buildDrafts", "D", false, "include content marked as draft")
cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future") cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
cmd.Flags().BoolP("buildExpired", "E", false, "include expired content") 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("contentDir", "c", "", "filesystem path to content directory")
cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory") cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/") 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().StringP("themesDir", "", "", "filesystem path to themes directory")
cmd.Flags().Bool("uglyURLs", false, "(deprecated) if true, use /filename.html instead of /filename/") 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().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().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().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") 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"}) _ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
} }
func initBenchmarkBuildingFlags(cmd *cobra.Command) { // Hugo represents the Hugo sites to build. This variable is exported as it
cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)") // 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. var (
func init() { hugoCommand = newHugoCmd()
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")
initRootPersistentFlags() // HugoCmd is Hugo's root command.
initHugoBuilderFlags(HugoCmd) // Every other command attached to HugoCmd is a child command to it.
initBenchmarkBuildingFlags(HugoCmd) HugoCmd = hugoCommand.getCommand()
)
HugoCmd.Flags().BoolVarP(&buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed") // Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
hugoCmdV = HugoCmd func Execute() {
HugoCmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)
// Set bash-completion HugoCmd.SilenceUsage = true
_ = HugoCmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
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. // 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 { if err != nil {
return nil, err 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 ( var (
logHandle = ioutil.Discard logHandle = ioutil.Discard
logThreshold = jww.LevelWarn logThreshold = jww.LevelWarn
@ -262,7 +287,7 @@ func createLogger(cfg config.Provider) (*jww.Notepad, error) {
stdoutThreshold = jww.LevelError stdoutThreshold = jww.LevelError
) )
if verboseLog || logging || (logFile != "") { if c.h.verboseLog || c.h.logging || (c.h.logFile != "") {
var err error var err error
if logFile != "" { if logFile != "" {
logHandle, err = os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) 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) return nil, newSystemError(err)
} }
} }
} else if !quiet && cfg.GetBool("verbose") { } else if !c.h.quiet && cfg.GetBool("verbose") {
stdoutThreshold = jww.LevelInfo stdoutThreshold = jww.LevelInfo
} }
@ -283,7 +308,7 @@ func createLogger(cfg config.Provider) (*jww.Notepad, error) {
stdoutThreshold = jww.LevelDebug stdoutThreshold = jww.LevelDebug
} }
if verboseLog { if c.h.verboseLog {
logThreshold = jww.LevelInfo logThreshold = jww.LevelInfo
if cfg.GetBool("debug") { if cfg.GetBool("debug") {
logThreshold = jww.LevelDebug logThreshold = jww.LevelDebug
@ -381,7 +406,7 @@ func (c *commandeer) fullBuild() error {
langCount map[string]uint64 langCount map[string]uint64
) )
if !quiet { if !c.h.quiet {
fmt.Print(hideCursor + "Building sites … ") fmt.Print(hideCursor + "Building sites … ")
defer func() { defer func() {
fmt.Print(showCursor + clearLine) fmt.Print(showCursor + clearLine)
@ -424,7 +449,7 @@ func (c *commandeer) fullBuild() error {
s.ProcessingStats.Static = langCount[s.Language.Lang] s.ProcessingStats.Static = langCount[s.Language.Lang]
} }
if gc { if c.h.gc {
count, err := Hugo.GC() count, err := Hugo.GC()
if err != nil { if err != nil {
return err return err
@ -447,13 +472,13 @@ func (c *commandeer) build() error {
} }
// TODO(bep) Feedback? // TODO(bep) Feedback?
if !quiet { if !c.h.quiet {
fmt.Println() fmt.Println()
Hugo.PrintProcessingStats(os.Stdout) Hugo.PrintProcessingStats(os.Stdout)
fmt.Println() fmt.Println()
} }
if buildWatch { if c.h.buildWatch {
watchDirs, err := c.getDirList() watchDirs, err := c.getDirList()
if err != nil { if err != nil {
return err return err
@ -481,7 +506,7 @@ func (c *commandeer) serverBuild() error {
} }
// TODO(bep) Feedback? // TODO(bep) Feedback?
if !quiet { if !c.h.quiet {
fmt.Println() fmt.Println()
Hugo.PrintProcessingStats(os.Stdout) Hugo.PrintProcessingStats(os.Stdout)
fmt.Println() 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) { func (c *commandeer) timeTrack(start time.Time, name string) {
if quiet { if c.h.quiet {
return return
} }
elapsed := time.Since(start) elapsed := time.Since(start)
@ -765,7 +790,7 @@ func (c *commandeer) recreateAndBuildSites(watching bool) (err error) {
if err := c.initSites(); err != nil { if err := c.initSites(); err != nil {
return err return err
} }
if !quiet { if !c.h.quiet {
c.Logger.FEEDBACK.Println("Started building sites ...") c.Logger.FEEDBACK.Println("Started building sites ...")
} }
return Hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true}) return Hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true})
@ -775,7 +800,7 @@ func (c *commandeer) resetAndBuildSites() (err error) {
if err = c.initSites(); err != nil { if err = c.initSites(); err != nil {
return return
} }
if !quiet { if !c.h.quiet {
c.Logger.FEEDBACK.Println("Started building sites ...") c.Logger.FEEDBACK.Println("Started building sites ...")
} }
return Hugo.Build(hugolib.BuildCfg{ResetState: true}) return Hugo.Build(hugolib.BuildCfg{ResetState: true})
@ -811,7 +836,7 @@ func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
return err return err
} }
visited := c.visitedURLs.PeekAllSet() visited := c.visitedURLs.PeekAllSet()
doLiveReload := !buildWatch && !c.Cfg.GetBool("disableLiveReload") doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload")
if doLiveReload && !c.Cfg.GetBool("disableFastRender") { if doLiveReload && !c.Cfg.GetBool("disableFastRender") {
// Make sure we always render the home pages // Make sure we always render the home pages
@ -833,7 +858,7 @@ func (c *commandeer) fullRebuild() {
jww.ERROR.Println("Failed to reload config:", err) jww.ERROR.Println("Failed to reload config:", err)
} else if err := c.recreateAndBuildSites(true); err != nil { } else if err := c.recreateAndBuildSites(true); err != nil {
jww.ERROR.Println(err) jww.ERROR.Println(err)
} else if !buildWatch && !c.Cfg.GetBool("disableLiveReload") { } else if !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload") {
livereload.ForceRefresh() 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 // 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 // force refresh when more than one file
@ -1030,7 +1055,7 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
} }
if len(dynamicEvents) > 0 { if len(dynamicEvents) > 0 {
doLiveReload := !buildWatch && !c.Cfg.GetBool("disableLiveReload") doLiveReload := !c.h.buildWatch && !c.Cfg.GetBool("disableLiveReload")
onePageName := pickOneWriteOrCreatePath(dynamicEvents) onePageName := pickOneWriteOrCreatePath(dynamicEvents)
c.Logger.FEEDBACK.Println("\nChange detected, rebuilding site") c.Logger.FEEDBACK.Println("\nChange detected, rebuilding site")

View file

@ -35,27 +35,23 @@ import (
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
) )
var _ cmder = (*newThemeCmd)(nil) var _ cmder = (*importCmd)(nil)
type importCmd struct { type importCmd struct {
cmd *cobra.Command *baseCmd
}
func (c *importCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newImportCmd() *importCmd { func newImportCmd() *importCmd {
cc := &importCmd{} cc := &importCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "import", Use: "import",
Short: "Import your site from others.", Short: "Import your site from others.",
Long: `Import your site from other web site generators like Jekyll. 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`.", Import requires a subcommand, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.",
RunE: nil, RunE: nil,
} })
importJekyllCmd := &cobra.Command{ importJekyllCmd := &cobra.Command{
Use: "jekyll", 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 { func (i *importCmd) importFromJekyll(cmd *cobra.Command, args []string) error {
if len(args) < 2 { if len(args) < 2 {

View file

@ -23,7 +23,7 @@ import (
var _ cmder = (*limitCmd)(nil) var _ cmder = (*limitCmd)(nil)
type limitCmd struct { type limitCmd struct {
cmd *cobra.Command *baseCmd
} }
func newLimitCmd() *limitCmd { 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} return &limitCmd{baseCmd: newBaseCmd(ccmd)}
}
func (c *limitCmd) getCommand() *cobra.Command {
return c.cmd
} }
func init() { func init() {

View file

@ -24,24 +24,21 @@ import (
var _ cmder = (*listCmd)(nil) var _ cmder = (*listCmd)(nil)
type listCmd struct { type listCmd struct {
cmd *cobra.Command hugoBuilderCommon
} *baseCmd
func (c *listCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newListCmd() *listCmd { func newListCmd() *listCmd {
cc := &listCmd{} cc := &listCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "list", Use: "list",
Short: "Listing out various types of content", Short: "Listing out various types of content",
Long: `Listing out various types of content. Long: `Listing out various types of content.
List requires a subcommand, e.g. ` + "`hugo list drafts`.", List requires a subcommand, e.g. ` + "`hugo list drafts`.",
RunE: nil, RunE: nil,
} })
cc.cmd.AddCommand( cc.cmd.AddCommand(
&cobra.Command{ &cobra.Command{
@ -53,7 +50,7 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
c.Set("buildDrafts", true) c.Set("buildDrafts", true)
return nil return nil
} }
c, err := InitializeConfig(false, cfgInit) c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil { if err != nil {
return err return err
} }
@ -89,7 +86,7 @@ posted in the future.`,
c.Set("buildFuture", true) c.Set("buildFuture", true)
return nil return nil
} }
c, err := InitializeConfig(false, cfgInit) c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil { if err != nil {
return err return err
} }
@ -125,7 +122,7 @@ expired.`,
c.Set("buildExpired", true) c.Set("buildExpired", true)
return nil return nil
} }
c, err := InitializeConfig(false, cfgInit) c, err := initializeConfig(false, &cc.hugoBuilderCommon, cc, cfgInit)
if err != nil { if err != nil {
return err 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{}) cc.cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
return cc return cc

View file

@ -25,27 +25,23 @@ import (
var _ cmder = (*configCmd)(nil) var _ cmder = (*configCmd)(nil)
type configCmd struct { type configCmd struct {
cmd *cobra.Command *baseCmd
}
func (c *configCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newConfigCmd() *configCmd { func newConfigCmd() *configCmd {
cc := &configCmd{} cc := &configCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "config", Use: "config",
Short: "Print the site configuration", Short: "Print the site configuration",
Long: `Print the site configuration, both default and custom settings.`, Long: `Print the site configuration, both default and custom settings.`,
RunE: cc.printConfig, RunE: cc.printConfig,
} })
return cc return cc
} }
func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error { 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 { if err != nil {
return err return err

View file

@ -33,15 +33,11 @@ type newCmd struct {
contentEditor string contentEditor string
contentType string contentType string
cmd *cobra.Command *baseCmd
}
func (c *newCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newNewCmd() *newCmd { func newNewCmd() *newCmd {
ccmd := &newCmd{} ccmd := &newCmd{baseCmd: newBaseCmd(nil)}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "new [path]", Use: "new [path]",
Short: "Create new content for your site", 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") cmd.Flags().StringVarP(&ccmd.contentType, "kind", "k", "", "content type to create")
// TODO(bep) cli refactor // 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.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
cmd.Flags().StringVar(&ccmd.contentEditor, "editor", "", "edit new content with this editor, if provided") 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 return nil
} }
c, err := InitializeConfig(false, cfgInit) c, err := initializeConfig(false, nil, n, cfgInit)
if err != nil { if err != nil {
return err return err

View file

@ -40,11 +40,7 @@ var _ cmder = (*newSiteCmd)(nil)
type newSiteCmd struct { type newSiteCmd struct {
configFormat string configFormat string
cmd *cobra.Command *baseCmd
}
func (c *newSiteCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newNewSiteCmd() *newSiteCmd { 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().StringVarP(&ccmd.configFormat, "format", "f", "toml", "config & frontmatter format")
cmd.Flags().Bool("force", false, "init inside non-empty directory") cmd.Flags().Bool("force", false, "init inside non-empty directory")
ccmd.cmd = cmd ccmd.baseCmd = newBaseCmd(cmd)
return ccmd return ccmd

View file

@ -31,15 +31,11 @@ import (
var _ cmder = (*newThemeCmd)(nil) var _ cmder = (*newThemeCmd)(nil)
type newThemeCmd struct { type newThemeCmd struct {
cmd *cobra.Command *baseCmd
}
func (c *newThemeCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newNewThemeCmd() *newThemeCmd { func newNewThemeCmd() *newThemeCmd {
ccmd := &newThemeCmd{} ccmd := &newThemeCmd{newBaseCmd(nil)}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "theme [name]", Use: "theme [name]",
@ -57,7 +53,7 @@ as you see fit.`,
} }
func (n *newThemeCmd) newTheme(cmd *cobra.Command, args []string) error { 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 { if err != nil {
return err return err

View file

@ -23,7 +23,8 @@ import (
) )
func init() { func init() {
HugoCmd.AddCommand(createReleaser().cmd) // TODO(bep) cli refactor
//HugoCmd.AddCommand(createReleaser().cmd)
} }
type releaseCommandeer struct { type releaseCommandeer struct {

View file

@ -38,9 +38,9 @@ import (
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
) )
var _ cmder = (*serverCmd)(nil)
type serverCmd struct { type serverCmd struct {
hugoBuilderCommon
disableLiveReload bool disableLiveReload bool
navigateToChanged bool navigateToChanged bool
renderToDisk bool renderToDisk bool
@ -53,17 +53,31 @@ type serverCmd struct {
disableFastRender bool disableFastRender bool
cmd *cobra.Command *baseCmd
} }
func (c *serverCmd) getCommand() *cobra.Command { func (cc *serverCmd) handleFlags(cmd *cobra.Command) {
return c.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\".")
} }
func newServerCmd() *serverCmd { func newServerCmd() *serverCmd {
cc := &serverCmd{} cc := &serverCmd{}
cc.cmd = &cobra.Command{ cc.baseCmd = newBaseCmd(&cobra.Command{
Use: "server", Use: "server",
Aliases: []string{"serve"}, Aliases: []string{"serve"},
Short: "A high performance webserver", 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 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.`, of a second, you will be able to save and see your changes nearly instantly.`,
RunE: cc.server, 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 return cc
} }
@ -122,10 +119,6 @@ func (f noDirFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil return nil, nil
} }
func init() {
}
var serverPorts []int var serverPorts []int
func (s *serverCmd) server(cmd *cobra.Command, args []string) error { 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] serverPort = serverPorts[0]
} }
baseURL, err := s.fixURL(language, baseURL, serverPort) baseURL, err := s.fixURL(language, s.baseURL, serverPort)
if err != nil { if err != nil {
return nil return nil
} }
@ -232,7 +225,7 @@ func (s *serverCmd) server(cmd *cobra.Command, args []string) error {
jww.ERROR.Println("memstats error:", err) 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 // TODO(bep) cli refactor
if err != nil { if err != nil {
return err return err
@ -308,7 +301,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
httpFs := afero.NewHttpFs(f.c.Fs.Destination) httpFs := afero.NewHttpFs(f.c.Fs.Destination)
fs := filesOnlyFs{httpFs.Dir(absPublishDir)} 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") fastRenderMode := doLiveReload && !f.c.Cfg.GetBool("disableFastRender")
if i == 0 && fastRenderMode { if i == 0 && fastRenderMode {

View file

@ -26,16 +26,12 @@ import (
var _ cmder = (*versionCmd)(nil) var _ cmder = (*versionCmd)(nil)
type versionCmd struct { type versionCmd struct {
cmd *cobra.Command *baseCmd
}
func (c *versionCmd) getCommand() *cobra.Command {
return c.cmd
} }
func newVersionCmd() *versionCmd { func newVersionCmd() *versionCmd {
return &versionCmd{ return &versionCmd{
&cobra.Command{ newBaseCmd(&cobra.Command{
Use: "version", Use: "version",
Short: "Print the version number of Hugo", Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's.`, Long: `All software has versions. This is Hugo's.`,
@ -43,7 +39,7 @@ func newVersionCmd() *versionCmd {
printHugoVersion() printHugoVersion()
return nil return nil
}, },
}, }),
} }
} }