github.com/whatlly/hugo@v0.47.1/commands/commands.go (about)

     1  // Copyright 2017 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package commands
    15  
    16  import (
    17  	"os"
    18  
    19  	"github.com/gohugoio/hugo/config"
    20  	"github.com/gohugoio/hugo/helpers"
    21  	"github.com/spf13/cobra"
    22  	jww "github.com/spf13/jwalterweatherman"
    23  
    24  	"github.com/spf13/nitro"
    25  )
    26  
    27  type commandsBuilder struct {
    28  	hugoBuilderCommon
    29  
    30  	commands []cmder
    31  }
    32  
    33  func newCommandsBuilder() *commandsBuilder {
    34  	return &commandsBuilder{}
    35  }
    36  
    37  func (b *commandsBuilder) addCommands(commands ...cmder) *commandsBuilder {
    38  	b.commands = append(b.commands, commands...)
    39  	return b
    40  }
    41  
    42  func (b *commandsBuilder) addAll() *commandsBuilder {
    43  	b.addCommands(
    44  		b.newServerCmd(),
    45  		newVersionCmd(),
    46  		newEnvCmd(),
    47  		newConfigCmd(),
    48  		newCheckCmd(),
    49  		b.newBenchmarkCmd(),
    50  		newConvertCmd(),
    51  		newNewCmd(),
    52  		newListCmd(),
    53  		newImportCmd(),
    54  		newGenCmd(),
    55  		createReleaser(),
    56  	)
    57  
    58  	return b
    59  }
    60  
    61  func (b *commandsBuilder) build() *hugoCmd {
    62  	h := b.newHugoCmd()
    63  	addCommands(h.getCommand(), b.commands...)
    64  	return h
    65  }
    66  
    67  func addCommands(root *cobra.Command, commands ...cmder) {
    68  	for _, command := range commands {
    69  		cmd := command.getCommand()
    70  		if cmd == nil {
    71  			continue
    72  		}
    73  		root.AddCommand(cmd)
    74  	}
    75  }
    76  
    77  type baseCmd struct {
    78  	cmd *cobra.Command
    79  }
    80  
    81  var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)
    82  
    83  // Used in tests.
    84  type commandsBuilderGetter interface {
    85  	getCmmandsBuilder() *commandsBuilder
    86  }
    87  type baseBuilderCmd struct {
    88  	*baseCmd
    89  	*commandsBuilder
    90  }
    91  
    92  func (b *baseBuilderCmd) getCmmandsBuilder() *commandsBuilder {
    93  	return b.commandsBuilder
    94  }
    95  
    96  func (c *baseCmd) getCommand() *cobra.Command {
    97  	return c.cmd
    98  }
    99  
   100  func newBaseCmd(cmd *cobra.Command) *baseCmd {
   101  	return &baseCmd{cmd: cmd}
   102  }
   103  
   104  func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
   105  	bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
   106  	bcmd.hugoBuilderCommon.handleFlags(cmd)
   107  	return bcmd
   108  }
   109  
   110  func (c *baseCmd) flagsToConfig(cfg config.Provider) {
   111  	initializeFlags(c.cmd, cfg)
   112  }
   113  
   114  type hugoCmd struct {
   115  	*baseBuilderCmd
   116  
   117  	// Need to get the sites once built.
   118  	c *commandeer
   119  }
   120  
   121  var _ cmder = (*nilCommand)(nil)
   122  
   123  type nilCommand struct {
   124  }
   125  
   126  func (c *nilCommand) getCommand() *cobra.Command {
   127  	return nil
   128  }
   129  
   130  func (c *nilCommand) flagsToConfig(cfg config.Provider) {
   131  
   132  }
   133  
   134  func (b *commandsBuilder) newHugoCmd() *hugoCmd {
   135  	cc := &hugoCmd{}
   136  
   137  	cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
   138  		Use:   "hugo",
   139  		Short: "hugo builds your site",
   140  		Long: `hugo is the main command, used to build your Hugo site.
   141  
   142  Hugo is a Fast and Flexible Static Site Generator
   143  built with love by spf13 and friends in Go.
   144  
   145  Complete documentation is available at http://gohugo.io/.`,
   146  		RunE: func(cmd *cobra.Command, args []string) error {
   147  			cfgInit := func(c *commandeer) error {
   148  				if cc.buildWatch {
   149  					c.Set("disableLiveReload", true)
   150  				}
   151  				return nil
   152  			}
   153  
   154  			c, err := initializeConfig(true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit)
   155  			if err != nil {
   156  				return err
   157  			}
   158  			cc.c = c
   159  
   160  			return c.build()
   161  		},
   162  	})
   163  
   164  	cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
   165  	cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode")
   166  
   167  	// Set bash-completion
   168  	validConfigFilenames := []string{"json", "js", "yaml", "yml", "toml", "tml"}
   169  	_ = cc.cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, validConfigFilenames)
   170  
   171  	cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output")
   172  	cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output")
   173  	cc.cmd.PersistentFlags().BoolVar(&cc.logging, "log", false, "enable Logging")
   174  	cc.cmd.PersistentFlags().StringVar(&cc.logFile, "logFile", "", "log File path (if set, logging enabled automatically)")
   175  	cc.cmd.PersistentFlags().BoolVar(&cc.verboseLog, "verboseLog", false, "verbose logging")
   176  
   177  	cc.cmd.Flags().BoolVarP(&cc.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
   178  
   179  	cc.cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)")
   180  	cc.cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)")
   181  
   182  	// Set bash-completion
   183  	_ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
   184  
   185  	cc.cmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)
   186  	cc.cmd.SilenceUsage = true
   187  
   188  	return cc
   189  }
   190  
   191  type hugoBuilderCommon struct {
   192  	source  string
   193  	baseURL string
   194  
   195  	buildWatch bool
   196  
   197  	gc bool
   198  
   199  	// TODO(bep) var vs string
   200  	logging    bool
   201  	verbose    bool
   202  	verboseLog bool
   203  	debug      bool
   204  	quiet      bool
   205  
   206  	cfgFile string
   207  	logFile string
   208  }
   209  
   210  func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
   211  	cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories")
   212  	cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft")
   213  	cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
   214  	cmd.Flags().BoolP("buildExpired", "E", false, "include expired content")
   215  	cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
   216  	cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
   217  	cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
   218  	cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
   219  	cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory")
   220  	cmd.Flags().StringP("destination", "d", "", "filesystem path to write files to")
   221  	cmd.Flags().StringP("theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
   222  	cmd.Flags().StringP("themesDir", "", "", "filesystem path to themes directory")
   223  	cmd.Flags().Bool("uglyURLs", false, "(deprecated) if true, use /filename.html instead of /filename/")
   224  	cmd.Flags().Bool("canonifyURLs", false, "(deprecated) if true, all relative URLs will be canonicalized using baseURL")
   225  	cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/")
   226  	cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages")
   227  	cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build")
   228  
   229  	cmd.Flags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
   230  	cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions")
   231  	cmd.Flags().Bool("templateMetricsHints", false, "calculate some improvement hints when combined with --templateMetrics")
   232  	cmd.Flags().Bool("pluralizeListTitles", true, "(deprecated) pluralize titles in lists using inflect")
   233  	cmd.Flags().Bool("preserveTaxonomyNames", false, `(deprecated) preserve taxonomy names as written ("GĂ©rard Depardieu" vs "gerard-depardieu")`)
   234  	cmd.Flags().BoolP("forceSyncStatic", "", false, "copy all files when static is changed.")
   235  	cmd.Flags().BoolP("noTimes", "", false, "don't sync modification time of files")
   236  	cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files")
   237  	cmd.Flags().BoolP("i18n-warnings", "", false, "print missing translations")
   238  
   239  	cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)")
   240  
   241  	// Set bash-completion.
   242  	// Each flag must first be defined before using the SetAnnotation() call.
   243  	_ = cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{})
   244  	_ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{})
   245  	_ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{})
   246  	_ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"})
   247  }
   248  
   249  func checkErr(logger *jww.Notepad, err error, s ...string) {
   250  	if err == nil {
   251  		return
   252  	}
   253  	if len(s) == 0 {
   254  		logger.CRITICAL.Println(err)
   255  		return
   256  	}
   257  	for _, message := range s {
   258  		logger.ERROR.Println(message)
   259  	}
   260  	logger.ERROR.Println(err)
   261  }
   262  
   263  func stopOnErr(logger *jww.Notepad, err error, s ...string) {
   264  	if err == nil {
   265  		return
   266  	}
   267  
   268  	defer os.Exit(-1)
   269  
   270  	if len(s) == 0 {
   271  		newMessage := err.Error()
   272  		// Printing an empty string results in a error with
   273  		// no message, no bueno.
   274  		if newMessage != "" {
   275  			logger.CRITICAL.Println(newMessage)
   276  		}
   277  	}
   278  	for _, message := range s {
   279  		if message != "" {
   280  			logger.CRITICAL.Println(message)
   281  		}
   282  	}
   283  }