github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/commands/commands.go (about) 1 // Copyright 2019 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 "fmt" 18 "os" 19 "time" 20 21 "github.com/gohugoio/hugo/hugolib/paths" 22 23 "github.com/gohugoio/hugo/common/hugo" 24 "github.com/gohugoio/hugo/common/loggers" 25 "github.com/gohugoio/hugo/config" 26 "github.com/gohugoio/hugo/helpers" 27 "github.com/spf13/cobra" 28 ) 29 30 type commandsBuilder struct { 31 hugoBuilderCommon 32 33 commands []cmder 34 } 35 36 func newCommandsBuilder() *commandsBuilder { 37 return &commandsBuilder{} 38 } 39 40 func (b *commandsBuilder) addCommands(commands ...cmder) *commandsBuilder { 41 b.commands = append(b.commands, commands...) 42 return b 43 } 44 45 func (b *commandsBuilder) addAll() *commandsBuilder { 46 b.addCommands( 47 b.newServerCmd(), 48 newVersionCmd(), 49 newEnvCmd(), 50 b.newConfigCmd(), 51 newCheckCmd(), 52 b.newDeployCmd(), 53 b.newConvertCmd(), 54 b.newNewCmd(), 55 b.newListCmd(), 56 newImportCmd(), 57 newGenCmd(), 58 createReleaser(), 59 b.newModCmd(), 60 ) 61 62 return b 63 } 64 65 func (b *commandsBuilder) build() *hugoCmd { 66 h := b.newHugoCmd() 67 addCommands(h.getCommand(), b.commands...) 68 return h 69 } 70 71 func addCommands(root *cobra.Command, commands ...cmder) { 72 for _, command := range commands { 73 cmd := command.getCommand() 74 if cmd == nil { 75 continue 76 } 77 root.AddCommand(cmd) 78 } 79 } 80 81 type baseCmd struct { 82 cmd *cobra.Command 83 } 84 85 var _ commandsBuilderGetter = (*baseBuilderCmd)(nil) 86 87 // Used in tests. 88 type commandsBuilderGetter interface { 89 getCommandsBuilder() *commandsBuilder 90 } 91 92 type baseBuilderCmd struct { 93 *baseCmd 94 *commandsBuilder 95 } 96 97 func (b *baseBuilderCmd) getCommandsBuilder() *commandsBuilder { 98 return b.commandsBuilder 99 } 100 101 func (c *baseCmd) getCommand() *cobra.Command { 102 return c.cmd 103 } 104 105 func newBaseCmd(cmd *cobra.Command) *baseCmd { 106 return &baseCmd{cmd: cmd} 107 } 108 109 func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd { 110 bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}} 111 bcmd.hugoBuilderCommon.handleFlags(cmd) 112 return bcmd 113 } 114 115 func (b *commandsBuilder) newBuilderBasicCmd(cmd *cobra.Command) *baseBuilderCmd { 116 bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}} 117 bcmd.hugoBuilderCommon.handleCommonBuilderFlags(cmd) 118 return bcmd 119 } 120 121 func (c *baseCmd) flagsToConfig(cfg config.Provider) { 122 initializeFlags(c.cmd, cfg) 123 } 124 125 type hugoCmd struct { 126 *baseBuilderCmd 127 128 // Need to get the sites once built. 129 c *commandeer 130 } 131 132 var _ cmder = (*nilCommand)(nil) 133 134 type nilCommand struct { 135 } 136 137 func (c *nilCommand) getCommand() *cobra.Command { 138 return nil 139 } 140 141 func (c *nilCommand) flagsToConfig(cfg config.Provider) { 142 } 143 144 func (b *commandsBuilder) newHugoCmd() *hugoCmd { 145 cc := &hugoCmd{} 146 147 cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{ 148 Use: "hugo", 149 Short: "hugo builds your site", 150 Long: `hugo is the main command, used to build your Hugo site. 151 152 Hugo is a Fast and Flexible Static Site Generator 153 built with love by spf13 and friends in Go. 154 155 Complete documentation is available at http://gohugo.io/.`, 156 RunE: func(cmd *cobra.Command, args []string) error { 157 defer cc.timeTrack(time.Now(), "Total") 158 cfgInit := func(c *commandeer) error { 159 if cc.buildWatch { 160 c.Set("disableLiveReload", true) 161 } 162 return nil 163 } 164 165 // prevent cobra printing error so it can be handled here (before the timeTrack prints) 166 cmd.SilenceErrors = true 167 168 c, err := initializeConfig(true, true, cc.buildWatch, &cc.hugoBuilderCommon, cc, cfgInit) 169 if err != nil { 170 cmd.PrintErrln("Error:", err.Error()) 171 return err 172 } 173 cc.c = c 174 175 err = c.build() 176 if err != nil { 177 cmd.PrintErrln("Error:", err.Error()) 178 } 179 return err 180 }, 181 }) 182 183 cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)") 184 cc.cmd.PersistentFlags().StringVar(&cc.cfgDir, "configDir", "config", "config dir") 185 cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode") 186 187 // Set bash-completion 188 _ = cc.cmd.PersistentFlags().SetAnnotation("config", cobra.BashCompFilenameExt, config.ValidConfigFileExtensions) 189 190 cc.cmd.PersistentFlags().BoolVarP(&cc.verbose, "verbose", "v", false, "verbose output") 191 cc.cmd.PersistentFlags().BoolVarP(&cc.debug, "debug", "", false, "debug output") 192 cc.cmd.PersistentFlags().BoolVar(&cc.logging, "log", false, "enable Logging") 193 cc.cmd.PersistentFlags().StringVar(&cc.logFile, "logFile", "", "log File path (if set, logging enabled automatically)") 194 cc.cmd.PersistentFlags().BoolVar(&cc.verboseLog, "verboseLog", false, "verbose logging") 195 196 cc.cmd.Flags().BoolVarP(&cc.buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed") 197 198 cc.cmd.Flags().Bool("renderToMemory", false, "render to memory (only useful for benchmark testing)") 199 200 // Set bash-completion 201 _ = cc.cmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{}) 202 203 cc.cmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags) 204 cc.cmd.SilenceUsage = true 205 206 return cc 207 } 208 209 type hugoBuilderCommon struct { 210 source string 211 baseURL string 212 environment string 213 214 buildWatch bool 215 poll string 216 217 gc bool 218 219 // Profile flags (for debugging of performance problems) 220 cpuprofile string 221 memprofile string 222 mutexprofile string 223 traceprofile string 224 printm bool 225 226 // TODO(bep) var vs string 227 logging bool 228 verbose bool 229 verboseLog bool 230 debug bool 231 quiet bool 232 233 cfgFile string 234 cfgDir string 235 logFile string 236 } 237 238 func (cc *hugoBuilderCommon) timeTrack(start time.Time, name string) { 239 if cc.quiet { 240 return 241 } 242 elapsed := time.Since(start) 243 fmt.Printf("%s in %v ms\n", name, int(1000*elapsed.Seconds())) 244 } 245 246 func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string { 247 if cc.cfgDir != "" { 248 return paths.AbsPathify(baseDir, cc.cfgDir) 249 } 250 251 if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found { 252 return paths.AbsPathify(baseDir, v) 253 } 254 255 return paths.AbsPathify(baseDir, "config") 256 } 257 258 func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string { 259 if cc.environment != "" { 260 return cc.environment 261 } 262 263 if v, found := os.LookupEnv("HUGO_ENVIRONMENT"); found { 264 return v 265 } 266 267 // Used by Netlify and Forestry 268 if v, found := os.LookupEnv("HUGO_ENV"); found { 269 return v 270 } 271 272 if isServer { 273 return hugo.EnvironmentDevelopment 274 } 275 276 return hugo.EnvironmentProduction 277 } 278 279 func (cc *hugoBuilderCommon) handleCommonBuilderFlags(cmd *cobra.Command) { 280 cmd.PersistentFlags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from") 281 cmd.PersistentFlags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) 282 cmd.PersistentFlags().StringVarP(&cc.environment, "environment", "e", "", "build environment") 283 cmd.PersistentFlags().StringP("themesDir", "", "", "filesystem path to themes directory") 284 cmd.PersistentFlags().BoolP("ignoreVendor", "", false, "ignores any _vendor directory") 285 cmd.PersistentFlags().StringP("ignoreVendorPaths", "", "", "ignores any _vendor for module paths matching the given Glob pattern") 286 } 287 288 func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) { 289 cc.handleCommonBuilderFlags(cmd) 290 cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories") 291 cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft") 292 cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future") 293 cmd.Flags().BoolP("buildExpired", "E", false, "include expired content") 294 cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory") 295 cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory") 296 cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/") 297 cmd.Flags().BoolP("ignoreCache", "", false, "ignores the cache directory") 298 cmd.Flags().StringP("destination", "d", "", "filesystem path to write files to") 299 cmd.Flags().StringSliceP("theme", "t", []string{}, "themes to use (located in /themes/THEMENAME/)") 300 cmd.Flags().StringVarP(&cc.baseURL, "baseURL", "b", "", "hostname (and path) to the root, e.g. http://spf13.com/") 301 cmd.Flags().Bool("enableGitInfo", false, "add Git revision, date and author info to the pages") 302 cmd.Flags().BoolVar(&cc.gc, "gc", false, "enable to run some cleanup tasks (remove unused cache files) after the build") 303 cmd.Flags().StringVar(&cc.poll, "poll", "", "set this to a poll interval, e.g --poll 700ms, to use a poll based approach to watch for file system changes") 304 305 cmd.Flags().Bool("templateMetrics", false, "display metrics about template executions") 306 cmd.Flags().Bool("templateMetricsHints", false, "calculate some improvement hints when combined with --templateMetrics") 307 cmd.Flags().BoolP("forceSyncStatic", "", false, "copy all files when static is changed.") 308 cmd.Flags().BoolP("noTimes", "", false, "don't sync modification time of files") 309 cmd.Flags().BoolP("noChmod", "", false, "don't sync permission mode of files") 310 cmd.Flags().BoolP("i18n-warnings", "", false, "print missing translations") 311 cmd.Flags().BoolP("path-warnings", "", false, "print warnings on duplicate target paths etc.") 312 cmd.Flags().StringVarP(&cc.cpuprofile, "profile-cpu", "", "", "write cpu profile to `file`") 313 cmd.Flags().StringVarP(&cc.memprofile, "profile-mem", "", "", "write memory profile to `file`") 314 cmd.Flags().BoolVarP(&cc.printm, "print-mem", "", false, "print memory usage to screen at intervals") 315 cmd.Flags().StringVarP(&cc.mutexprofile, "profile-mutex", "", "", "write Mutex profile to `file`") 316 cmd.Flags().StringVarP(&cc.traceprofile, "trace", "", "", "write trace to `file` (not useful in general)") 317 318 // Hide these for now. 319 cmd.Flags().MarkHidden("profile-cpu") 320 cmd.Flags().MarkHidden("profile-mem") 321 cmd.Flags().MarkHidden("profile-mutex") 322 323 cmd.Flags().StringSlice("disableKinds", []string{}, "disable different kind of pages (home, RSS etc.)") 324 325 cmd.Flags().Bool("minify", false, "minify any supported output format (HTML, XML etc.)") 326 327 // Set bash-completion. 328 // Each flag must first be defined before using the SetAnnotation() call. 329 _ = cmd.Flags().SetAnnotation("source", cobra.BashCompSubdirsInDir, []string{}) 330 _ = cmd.Flags().SetAnnotation("cacheDir", cobra.BashCompSubdirsInDir, []string{}) 331 _ = cmd.Flags().SetAnnotation("destination", cobra.BashCompSubdirsInDir, []string{}) 332 _ = cmd.Flags().SetAnnotation("theme", cobra.BashCompSubdirsInDir, []string{"themes"}) 333 } 334 335 func checkErr(logger loggers.Logger, err error, s ...string) { 336 if err == nil { 337 return 338 } 339 for _, message := range s { 340 logger.Errorln(message) 341 } 342 logger.Errorln(err) 343 }