shithub: hugo

Download patch

ref: 00d04774f0d9789262557af6a6465d8b6271839d
parent: c9526f6e3fdffe9e583e11d3513faa392576c305
author: Anthony Fok <foka@debian.org>
date: Wed Dec 2 07:00:47 EST 2015

Change most global flags into local ones

This is to ensure that only the relevant command-line flags
for a certain Hugo subcommand is shown to the end user,
reducing clutter and improving user experience.

Fixes #1624 - CLI UX: Flags shouldn't be global

--- a/commands/benchmark.go
+++ b/commands/benchmark.go
@@ -28,23 +28,23 @@
 	Short: "Benchmark hugo by building a site a number of times.",
 	Long: `Hugo can build a site many times over and analyze the running process
 creating a benchmark.`,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		if err := InitializeConfig(); err != nil {
-			return err
-		}
-
-		return bench(cmd, args)
-	},
 }
 
 func init() {
+	initCoreCommonFlags(benchmarkCmd)
+
 	benchmarkCmd.Flags().StringVar(&cpuProfilefile, "cpuprofile", "", "path/filename for the CPU profile file")
 	benchmarkCmd.Flags().StringVar(&memProfilefile, "memprofile", "", "path/filename for the memory profile file")
 
 	benchmarkCmd.Flags().IntVarP(&benchmarkTimes, "count", "n", 13, "number of times to build the site")
+
+	benchmarkCmd.RunE = benchmark
 }
 
-func bench(cmd *cobra.Command, args []string) error {
+func benchmark(cmd *cobra.Command, args []string) error {
+	if err := InitializeConfig(benchmarkCmd); err != nil {
+		return err
+	}
 
 	if memProfilefile != "" {
 		f, err := os.Create(memProfilefile)
--- a/commands/check.go
+++ b/commands/check.go
@@ -23,13 +23,18 @@
 	Short: "Check content in the source directory",
 	Long: `Hugo will perform some basic analysis on the content provided
 and will give feedback.`,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		if err := InitializeConfig(); err != nil {
-			return err
-		}
-		site := hugolib.Site{}
+}
 
-		return site.Analyze()
+func init() {
+	initCoreCommonFlags(checkCmd)
+	checkCmd.RunE = check
+}
 
-	},
+func check(cmd *cobra.Command, args []string) error {
+	if err := InitializeConfig(checkCmd); err != nil {
+		return err
+	}
+	site := hugolib.Site{}
+
+	return site.Analyze()
 }
--- a/commands/convert.go
+++ b/commands/convert.go
@@ -74,6 +74,7 @@
 	convertCmd.AddCommand(toTOMLCmd)
 	convertCmd.AddCommand(toYAMLCmd)
 	convertCmd.PersistentFlags().StringVarP(&outputDir, "output", "o", "", "filesystem path to write files to")
+	convertCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
 	convertCmd.PersistentFlags().BoolVar(&unsafe, "unsafe", false, "enable less safe operations, please backup first")
 }
 
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -149,44 +149,52 @@
 	genCmd.AddCommand(genautocompleteCmd)
 	genCmd.AddCommand(gendocCmd)
 	genCmd.AddCommand(genmanCmd)
+}
 
+// initCoreCommonFlags initializes common flags used by Hugo core commands
+// such as hugo itself, server, check, config and benchmark.
+func initCoreCommonFlags(cmd *cobra.Command) {
+	cmd.Flags().BoolVarP(&Draft, "buildDrafts", "D", false, "include content marked as draft")
+	cmd.Flags().BoolVarP(&Future, "buildFuture", "F", false, "include content with publishdate in the future")
+	cmd.Flags().BoolVar(&DisableRSS, "disableRSS", false, "Do not build RSS files")
+	cmd.Flags().BoolVar(&DisableSitemap, "disableSitemap", false, "Do not build Sitemap file")
+	cmd.Flags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
+	cmd.Flags().StringVarP(&CacheDir, "cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
+	cmd.Flags().BoolVarP(&IgnoreCache, "ignoreCache", "", false, "Ignores the cache directory for reading but still writes to it")
+	cmd.Flags().StringVarP(&Destination, "destination", "d", "", "filesystem path to write files to")
+	cmd.Flags().StringVarP(&Theme, "theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
+	cmd.Flags().BoolVar(&UglyURLs, "uglyURLs", false, "if true, use /filename.html instead of /filename/")
+	cmd.Flags().BoolVar(&CanonifyURLs, "canonifyURLs", false, "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().StringVar(&CfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
+	cmd.Flags().StringVar(&Editor, "editor", "", "edit new content with this editor, if provided")
+	cmd.Flags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
+	cmd.Flags().BoolVar(&PluralizeListTitles, "pluralizeListTitles", true, "Pluralize titles in lists using inflect")
+	cmd.Flags().BoolVar(&PreserveTaxonomyNames, "preserveTaxonomyNames", false, `Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")`)
+
+	// For bash-completion
+	validConfigFilenames := []string{"json", "js", "yaml", "yml", "toml", "tml"}
+	cmd.Flags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames)
+	cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
+	cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
+	cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
+	cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
 }
 
 // init initializes flags.
 func init() {
-	HugoCmd.PersistentFlags().BoolVarP(&Draft, "buildDrafts", "D", false, "include content marked as draft")
-	HugoCmd.PersistentFlags().BoolVarP(&Future, "buildFuture", "F", false, "include content with publishdate in the future")
-	HugoCmd.PersistentFlags().BoolVar(&DisableRSS, "disableRSS", false, "Do not build RSS files")
-	HugoCmd.PersistentFlags().BoolVar(&DisableSitemap, "disableSitemap", false, "Do not build Sitemap file")
-	HugoCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
-	HugoCmd.PersistentFlags().StringVarP(&CacheDir, "cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
-	HugoCmd.PersistentFlags().BoolVarP(&IgnoreCache, "ignoreCache", "", false, "Ignores the cache directory for reading but still writes to it")
-	HugoCmd.PersistentFlags().StringVarP(&Destination, "destination", "d", "", "filesystem path to write files to")
-	HugoCmd.PersistentFlags().StringVarP(&Theme, "theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
 	HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
-	HugoCmd.PersistentFlags().BoolVar(&UglyURLs, "uglyURLs", false, "if true, use /filename.html instead of /filename/")
-	HugoCmd.PersistentFlags().BoolVar(&CanonifyURLs, "canonifyURLs", false, "if true, all relative URLs will be canonicalized using baseURL")
-	HugoCmd.PersistentFlags().StringVarP(&BaseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
-	HugoCmd.PersistentFlags().StringVar(&CfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
-	HugoCmd.PersistentFlags().StringVar(&Editor, "editor", "", "edit new content with this editor, if provided")
 	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")
-	HugoCmd.PersistentFlags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
-	HugoCmd.PersistentFlags().BoolVar(&PluralizeListTitles, "pluralizeListTitles", true, "Pluralize titles in lists using inflect")
-	HugoCmd.PersistentFlags().BoolVar(&PreserveTaxonomyNames, "preserveTaxonomyNames", false, `Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")`)
 
+	initCoreCommonFlags(HugoCmd)
+
 	HugoCmd.Flags().BoolVarP(&BuildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
 	HugoCmd.Flags().BoolVarP(&NoTimes, "noTimes", "", false, "Don't sync modification time of files")
 	hugoCmdV = HugoCmd
 
 	// For bash-completion
-	validConfigFilenames := []string{"json", "js", "yaml", "yml", "toml", "tml"}
-	HugoCmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames)
-	HugoCmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
-	HugoCmd.PersistentFlags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
-	HugoCmd.PersistentFlags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
-	HugoCmd.PersistentFlags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
 	HugoCmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
 
 	// This message will be shown to Windows users if Hugo is opened from explorer.exe
@@ -241,7 +249,9 @@
 }
 
 // InitializeConfig initializes a config file with sensible default configuration flags.
-func InitializeConfig() error {
+// A Hugo command that calls initCoreCommonFlags() can pass itself
+// as an argument to have its command-line flags processed here.
+func InitializeConfig(subCmdVs ...*cobra.Command) error {
 	viper.SetConfigFile(CfgFile)
 	// See https://github.com/spf13/viper/issues/73#issuecomment-126970794
 	if Source == "" {
@@ -262,52 +272,47 @@
 
 	LoadDefaultSettings()
 
-	if hugoCmdV.PersistentFlags().Lookup("buildDrafts").Changed {
-		viper.Set("BuildDrafts", Draft)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("buildFuture").Changed {
-		viper.Set("BuildFuture", Future)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("uglyURLs").Changed {
-		viper.Set("UglyURLs", UglyURLs)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("canonifyURLs").Changed {
-		viper.Set("CanonifyURLs", CanonifyURLs)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("disableRSS").Changed {
-		viper.Set("DisableRSS", DisableRSS)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("disableSitemap").Changed {
-		viper.Set("DisableSitemap", DisableSitemap)
-	}
-
 	if hugoCmdV.PersistentFlags().Lookup("verbose").Changed {
 		viper.Set("Verbose", Verbose)
 	}
-
-	if hugoCmdV.PersistentFlags().Lookup("pluralizeListTitles").Changed {
-		viper.Set("PluralizeListTitles", PluralizeListTitles)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("preserveTaxonomyNames").Changed {
-		viper.Set("PreserveTaxonomyNames", PreserveTaxonomyNames)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("editor").Changed {
-		viper.Set("NewContentEditor", Editor)
-	}
-
 	if hugoCmdV.PersistentFlags().Lookup("logFile").Changed {
 		viper.Set("LogFile", LogFile)
 	}
 
-	if hugoCmdV.Flags().Lookup("noTimes").Changed {
-		viper.Set("noTimes", NoTimes)
+	for _, cmdV := range append([]*cobra.Command{hugoCmdV}, subCmdVs...) {
+		if cmdV.Flags().Lookup("buildDrafts").Changed {
+			viper.Set("BuildDrafts", Draft)
+		}
+		if cmdV.Flags().Lookup("buildFuture").Changed {
+			viper.Set("BuildFuture", Future)
+		}
+		if cmdV.Flags().Lookup("uglyURLs").Changed {
+			viper.Set("UglyURLs", UglyURLs)
+		}
+		if cmdV.Flags().Lookup("canonifyURLs").Changed {
+			viper.Set("CanonifyURLs", CanonifyURLs)
+		}
+		if cmdV.Flags().Lookup("disableRSS").Changed {
+			viper.Set("DisableRSS", DisableRSS)
+		}
+		if cmdV.Flags().Lookup("disableSitemap").Changed {
+			viper.Set("DisableSitemap", DisableSitemap)
+		}
+		if cmdV.Flags().Lookup("pluralizeListTitles").Changed {
+			viper.Set("PluralizeListTitles", PluralizeListTitles)
+		}
+		if cmdV.Flags().Lookup("preserveTaxonomyNames").Changed {
+			viper.Set("PreserveTaxonomyNames", PreserveTaxonomyNames)
+		}
+		if cmdV.Flags().Lookup("editor").Changed {
+			viper.Set("NewContentEditor", Editor)
+		}
+		if cmdV.Flags().Lookup("ignoreCache").Changed {
+			viper.Set("IgnoreCache", IgnoreCache)
+		}
+		if cmdV.Flags().Lookup("noTimes").Changed {
+			viper.Set("NoTimes", NoTimes)
+		}
 	}
 
 	if BaseURL != "" {
@@ -334,10 +339,6 @@
 	} else {
 		dir, _ := os.Getwd()
 		viper.Set("WorkingDir", dir)
-	}
-
-	if hugoCmdV.PersistentFlags().Lookup("ignoreCache").Changed {
-		viper.Set("IgnoreCache", IgnoreCache)
 	}
 
 	if CacheDir != "" {
--- a/commands/list.go
+++ b/commands/list.go
@@ -25,6 +25,7 @@
 func init() {
 	listCmd.AddCommand(listDraftsCmd)
 	listCmd.AddCommand(listFutureCmd)
+	listCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
 }
 
 var listCmd = &cobra.Command{
--- a/commands/list_config.go
+++ b/commands/list_config.go
@@ -25,34 +25,40 @@
 	Use:   "config",
 	Short: "Print the site configuration",
 	Long:  `Print the site configuration, both default and custom settings.`,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		if err := InitializeConfig(); err != nil {
-			return err
-		}
+}
 
-		allSettings := viper.AllSettings()
+func init() {
+	initCoreCommonFlags(configCmd)
+	configCmd.RunE = config
+}
 
-		var separator string
-		if allSettings["metadataformat"] == "toml" {
-			separator = " = "
+func config(cmd *cobra.Command, args []string) error {
+	if err := InitializeConfig(configCmd); err != nil {
+		return err
+	}
+
+	allSettings := viper.AllSettings()
+
+	var separator string
+	if allSettings["metadataformat"] == "toml" {
+		separator = " = "
+	} else {
+		separator = ": "
+	}
+
+	var keys []string
+	for k := range allSettings {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for _, k := range keys {
+		kv := reflect.ValueOf(allSettings[k])
+		if kv.Kind() == reflect.String {
+			fmt.Printf("%s%s\"%+v\"\n", k, separator, allSettings[k])
 		} else {
-			separator = ": "
+			fmt.Printf("%s%s%+v\n", k, separator, allSettings[k])
 		}
+	}
 
-		var keys []string
-		for k := range allSettings {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
-		for _, k := range keys {
-			kv := reflect.ValueOf(allSettings[k])
-			if kv.Kind() == reflect.String {
-				fmt.Printf("%s%s\"%+v\"\n", k, separator, allSettings[k])
-			} else {
-				fmt.Printf("%s%s%+v\n", k, separator, allSettings[k])
-			}
-		}
-
-		return nil
-	},
+	return nil
 }
--- a/commands/server.go
+++ b/commands/server.go
@@ -81,6 +81,7 @@
 }
 
 func init() {
+	initCoreCommonFlags(serverCmd)
 	serverCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
 	serverCmd.Flags().StringVarP(&serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
 	serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
@@ -94,7 +95,7 @@
 }
 
 func server(cmd *cobra.Command, args []string) error {
-	if err := InitializeConfig(); err != nil {
+	if err := InitializeConfig(serverCmd); err != nil {
 		return err
 	}
 
--