diff --git a/commands/benchmark.go b/commands/benchmark.go index a55ed7535..530bf3906 100644 --- a/commands/benchmark.go +++ b/commands/benchmark.go @@ -28,9 +28,12 @@ var benchmark = &cobra.Command{ 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.`, - Run: func(cmd *cobra.Command, args []string) { - InitializeConfig() - bench(cmd, args) + RunE: func(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } + + return bench(cmd, args) }, } @@ -41,13 +44,13 @@ func init() { benchmark.Flags().IntVarP(&benchmarkTimes, "count", "n", 13, "number of times to build the site") } -func bench(cmd *cobra.Command, args []string) { +func bench(cmd *cobra.Command, args []string) error { if memProfilefile != "" { f, err := os.Create(memProfilefile) if err != nil { - panic(err) + return err } for i := 0; i < benchmarkTimes; i++ { _ = buildSite() @@ -62,7 +65,7 @@ func bench(cmd *cobra.Command, args []string) { f, err := os.Create(cpuProfilefile) if err != nil { - panic(err) + return err } pprof.StartCPUProfile(f) @@ -72,4 +75,6 @@ func bench(cmd *cobra.Command, args []string) { } } + return nil + } diff --git a/commands/check.go b/commands/check.go index 0c8b3ba79..f17602246 100644 --- a/commands/check.go +++ b/commands/check.go @@ -23,9 +23,13 @@ var check = &cobra.Command{ Short: "Check content in the source directory", Long: `Hugo will perform some basic analysis on the content provided and will give feedback.`, - Run: func(cmd *cobra.Command, args []string) { - InitializeConfig() + RunE: func(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } site := hugolib.Site{} - site.Analyze() + + return site.Analyze() + }, } diff --git a/commands/convert.go b/commands/convert.go index 9f7076d7b..3e66ba2bf 100644 --- a/commands/convert.go +++ b/commands/convert.go @@ -36,7 +36,7 @@ var convertCmd = &cobra.Command{ Long: `Convert your content (e.g. front matter) to different formats. See convert's subcommands toJSON, toTOML and toYAML for more information.`, - Run: nil, + RunE: nil, } var toJSONCmd = &cobra.Command{ @@ -44,11 +44,8 @@ var toJSONCmd = &cobra.Command{ Short: "Convert front matter to JSON", Long: `toJSON converts all front matter in the content directory to use JSON for the front matter.`, - Run: func(cmd *cobra.Command, args []string) { - err := convertContents(rune([]byte(parser.JSON_LEAD)[0])) - if err != nil { - jww.ERROR.Println(err) - } + RunE: func(cmd *cobra.Command, args []string) error { + return convertContents(rune([]byte(parser.JSON_LEAD)[0])) }, } @@ -57,11 +54,8 @@ var toTOMLCmd = &cobra.Command{ Short: "Convert front matter to TOML", Long: `toTOML converts all front matter in the content directory to use TOML for the front matter.`, - Run: func(cmd *cobra.Command, args []string) { - err := convertContents(rune([]byte(parser.TOML_LEAD)[0])) - if err != nil { - jww.ERROR.Println(err) - } + RunE: func(cmd *cobra.Command, args []string) error { + return convertContents(rune([]byte(parser.TOML_LEAD)[0])) }, } @@ -70,11 +64,8 @@ var toYAMLCmd = &cobra.Command{ Short: "Convert front matter to YAML", Long: `toYAML converts all front matter in the content directory to use YAML for the front matter.`, - Run: func(cmd *cobra.Command, args []string) { - err := convertContents(rune([]byte(parser.YAML_LEAD)[0])) - if err != nil { - jww.ERROR.Println(err) - } + RunE: func(cmd *cobra.Command, args []string) error { + return convertContents(rune([]byte(parser.YAML_LEAD)[0])) }, } @@ -87,7 +78,9 @@ func init() { } func convertContents(mark rune) (err error) { - InitializeConfig() + if err := InitializeConfig(); err != nil { + return err + } site := &hugolib.Site{} if err := site.Initialise(); err != nil { diff --git a/commands/genautocomplete.go b/commands/genautocomplete.go index b7f74fd89..54dd7563b 100644 --- a/commands/genautocomplete.go +++ b/commands/genautocomplete.go @@ -31,16 +31,19 @@ or just source them in directly: $ . /etc/bash_completion`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if autocompleteType != "bash" { - jww.FATAL.Fatalln("Only Bash is supported for now") + return newUserError("Only Bash is supported for now") } + err := cmd.Root().GenBashCompletionFile(autocompleteTarget) + if err != nil { - jww.FATAL.Fatalln("Failed to generate shell completion file:", err) + return err } else { jww.FEEDBACK.Println("Bash completion file for Hugo saved to", autocompleteTarget) } + return nil }, } diff --git a/commands/gendoc.go b/commands/gendoc.go index 9589bffa4..44d09fb50 100644 --- a/commands/gendoc.go +++ b/commands/gendoc.go @@ -32,7 +32,7 @@ of Hugo's command-line interface for http://gohugo.io/. It creates one Markdown file per command with front matter suitable for rendering in Hugo.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if !strings.HasSuffix(gendocdir, helpers.FilePathSeparator) { gendocdir += helpers.FilePathSeparator } @@ -55,6 +55,8 @@ for rendering in Hugo.`, jww.FEEDBACK.Println("Generating Hugo command-line documentation in", gendocdir, "...") cobra.GenMarkdownTreeCustom(cmd.Root(), gendocdir, prepender, linkHandler) jww.FEEDBACK.Println("Done.") + + return nil }, } diff --git a/commands/genman.go b/commands/genman.go index 68a98a46d..a842b49b8 100644 --- a/commands/genman.go +++ b/commands/genman.go @@ -18,7 +18,7 @@ var genmanCmd = &cobra.Command{ command-line interface. By default, it creates the man page files in the "man" directory under the current directory.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { header := &cobra.GenManHeader{ Section: "1", Manual: "Hugo Manual", @@ -37,6 +37,8 @@ in the "man" directory under the current directory.`, cmd.Root().GenManTree(header, genmandir) jww.FEEDBACK.Println("Done.") + + return nil }, } diff --git a/commands/hugo.go b/commands/hugo.go index 2a72f535e..6724b794d 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -40,8 +40,44 @@ import ( "github.com/spf13/nitro" "github.com/spf13/viper" "gopkg.in/fsnotify.v1" + "regexp" ) +// userError is an error used to signal different error situations in command handling. +type commandError struct { + s string + userError bool +} + +func (u commandError) Error() string { + return u.s +} + +func (u commandError) isUserError() bool { + return u.userError +} + +func newUserError(messages ...interface{}) commandError { + return commandError{s: fmt.Sprintln(messages...), userError: true} +} + +func newSystemError(messages ...interface{}) commandError { + return commandError{s: fmt.Sprintln(messages...), userError: false} +} + +// catch some of the obvious user errors from Cobra. +// We don't want to show the usage message for every error. +// The below may be to generic. Time will show. +var userErrorRegexp = regexp.MustCompile("argument|flag|shorthand") + +func isUserError(err error) bool { + if cErr, ok := err.(commandError); ok && cErr.isUserError() { + return true + } + + return userErrorRegexp.MatchString(err.Error()) +} + //HugoCmd is Hugo's root command. Every other command attached to HugoCmd is a child command to it. var HugoCmd = &cobra.Command{ Use: "hugo", @@ -52,10 +88,15 @@ 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/.`, - Run: func(cmd *cobra.Command, args []string) { - InitializeConfig() + RunE: func(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } + watchConfig() - build() + + return build() + }, } @@ -68,9 +109,17 @@ var Source, CacheDir, Destination, Theme, BaseURL, CfgFile, LogFile, Editor stri //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 err := HugoCmd.Execute(); err != nil { - // the err is already logged by Cobra + + if c, err := HugoCmd.ExecuteC(); err != nil { + if isUserError(err) { + c.Println("") + c.Println(c.UsageString()) + } + os.Exit(-1) } } @@ -184,7 +233,7 @@ func LoadDefaultSettings() { } // InitializeConfig initializes a config file with sensible default configuration flags. -func InitializeConfig() { +func InitializeConfig() error { viper.SetConfigFile(CfgFile) // See https://github.com/spf13/viper/issues/73#issuecomment-126970794 if Source == "" { @@ -195,9 +244,9 @@ func InitializeConfig() { err := viper.ReadInConfig() if err != nil { if _, ok := err.(viper.ConfigParseError); ok { - jww.ERROR.Println(err) + return newSystemError(err) } else { - jww.ERROR.Println("Unable to locate Config file. Perhaps you need to create a new site. Run `hugo help new` for details", err) + return newSystemError("Unable to locate Config file. Perhaps you need to create a new site. Run `hugo help new` for details", err) } } @@ -320,7 +369,7 @@ func InitializeConfig() { themeDir := helpers.GetThemeDir() if themeDir != "" { if _, err := os.Stat(themeDir); os.IsNotExist(err) { - jww.FATAL.Fatalln("Unable to find theme Directory:", themeDir) + return newSystemError("Unable to find theme Directory:", themeDir) } } @@ -330,6 +379,8 @@ func InitializeConfig() { jww.ERROR.Printf("Current theme does not support Hugo version %s. Minimum version required is %s\n", helpers.HugoReleaseVersion(), minVersion) } + + return nil } func watchConfig() { @@ -344,23 +395,26 @@ func watchConfig() { }) } -func build(watches ...bool) { - err := copyStatic() - if err != nil { - fmt.Println(err) - utils.StopOnErr(err, fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir")))) +func build(watches ...bool) error { + + if err := copyStatic(); err != nil { + return fmt.Errorf("Error copying static files to %s: %s", helpers.AbsPathify(viper.GetString("PublishDir")), err) } watch := false if len(watches) > 0 && watches[0] { watch = true } - utils.StopOnErr(buildSite(BuildWatch || watch)) + if err := buildSite(BuildWatch || watch); err != nil { + return fmt.Errorf("Error building site: %s", err) + } if BuildWatch { jww.FEEDBACK.Println("Watching for changes in", helpers.AbsPathify(viper.GetString("ContentDir"))) jww.FEEDBACK.Println("Press Ctrl+C to stop") utils.CheckErr(NewWatcher(0)) } + + return nil } func copyStatic() error { @@ -483,7 +537,6 @@ func NewWatcher(port int) error { var wg sync.WaitGroup if err != nil { - fmt.Println(err) return err } diff --git a/commands/import.go b/commands/import.go deleted file mode 100644 index 830d970c2..000000000 --- a/commands/import.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright © 2015 Steve Francia . -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package commands - -import ( - "github.com/spf13/cobra" -) - -var importCmd = &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`.", - Run: nil, -} - -func init() { - importCmd.AddCommand(importJekyllCmd) -} diff --git a/commands/import_jekyll.go b/commands/import_jekyll.go index 38d352671..00893f854 100644 --- a/commands/import_jekyll.go +++ b/commands/import_jekyll.go @@ -35,34 +35,44 @@ import ( jww "github.com/spf13/jwalterweatherman" ) +func init() { + importCmd.AddCommand(importJekyllCmd) +} + +var importCmd = &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, +} + var importJekyllCmd = &cobra.Command{ Use: "jekyll", Short: "hugo import from Jekyll", Long: `hugo import from Jekyll. Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.", - Run: importFromJekyll, + RunE: importFromJekyll, } -func importFromJekyll(cmd *cobra.Command, args []string) { +func importFromJekyll(cmd *cobra.Command, args []string) error { jww.SetLogThreshold(jww.LevelTrace) jww.SetStdoutThreshold(jww.LevelWarn) if len(args) < 2 { - jww.ERROR.Println(`Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.") - return + return newUserError(`Import from Jekyll requires two paths, e.g. ` + "`hugo import jekyll jekyll_root_path target_path`.") } jekyllRoot, err := filepath.Abs(filepath.Clean(args[0])) if err != nil { - jww.ERROR.Println("Path error:", args[0]) - return + return newUserError("Path error:", args[0]) } targetDir, err := filepath.Abs(filepath.Clean(args[1])) if err != nil { - jww.ERROR.Println("Path error:", args[1]) - return + return newUserError("Path error:", args[1]) } createSiteFromJekyll(jekyllRoot, targetDir) @@ -82,8 +92,7 @@ func importFromJekyll(cmd *cobra.Command, args []string) { relPath, err := filepath.Rel(jekyllRoot, path) if err != nil { - jww.ERROR.Println("Get rel path error:", path) - return err + return newUserError("Get rel path error:", path) } relPath = filepath.ToSlash(relPath) @@ -106,13 +115,15 @@ func importFromJekyll(cmd *cobra.Command, args []string) { err = filepath.Walk(jekyllRoot, callback) if err != nil { - fmt.Println(err) + return err } else { fmt.Println("Congratulations!", fileCount, "posts imported!") fmt.Println("Now, start Hugo by yourself: \n" + "$ git clone https://github.com/spf13/herring-cove.git " + args[1] + "/themes/herring-cove") fmt.Println("$ cd " + args[1] + "\n$ hugo server -w --theme=herring-cove") } + + return nil } func createSiteFromJekyll(jekyllRoot, targetDir string) { diff --git a/commands/limit_darwin.go b/commands/limit_darwin.go index 274505073..ab8dba0f7 100644 --- a/commands/limit_darwin.go +++ b/commands/limit_darwin.go @@ -30,12 +30,13 @@ var limit = &cobra.Command{ Short: "Check system ulimit settings", Long: `Hugo will inspect the current ulimit settings on the system. This is primarily to ensure that Hugo can watch enough files on some OSs`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { var rLimit syscall.Rlimit err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) if err != nil { - jww.ERROR.Println("Error Getting Rlimit ", err) + return newSystemError("Error Getting Rlimit ", err) } + jww.FEEDBACK.Println("Current rLimit:", rLimit) jww.FEEDBACK.Println("Attempting to increase limit") @@ -43,13 +44,15 @@ var limit = &cobra.Command{ rLimit.Cur = 999999 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) if err != nil { - jww.ERROR.Println("Error Setting rLimit ", err) + return newSystemError("Error Setting rLimit ", err) } err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) if err != nil { - jww.ERROR.Println("Error Getting rLimit ", err) + return newSystemError("Error Getting rLimit ", err) } jww.FEEDBACK.Println("rLimit after change:", rLimit) + + return nil }, } diff --git a/commands/list.go b/commands/list.go index 2e85a8765..b3af0ef63 100644 --- a/commands/list.go +++ b/commands/list.go @@ -33,22 +33,25 @@ var listCmd = &cobra.Command{ Long: `Listing out various types of content. List requires a subcommand, e.g. ` + "`hugo list drafts`.", - Run: nil, + RunE: nil, } var listDraftsCmd = &cobra.Command{ Use: "drafts", Short: "List all drafts", Long: `List all of the drafts in your content directory.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { + + if err := InitializeConfig(); err != nil { + return err + } - InitializeConfig() viper.Set("BuildDrafts", true) site := &hugolib.Site{} if err := site.Process(); err != nil { - fmt.Println("Error Processing Source Content", err) + return newSystemError("Error Processing Source Content", err) } for _, p := range site.Pages { @@ -58,6 +61,8 @@ var listDraftsCmd = &cobra.Command{ } + return nil + }, } @@ -66,15 +71,18 @@ var listFutureCmd = &cobra.Command{ Short: "List all posts dated in the future", Long: `List all of the posts in your content directory which will be posted in the future.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { + + if err := InitializeConfig(); err != nil { + return err + } - InitializeConfig() viper.Set("BuildFuture", true) site := &hugolib.Site{} if err := site.Process(); err != nil { - fmt.Println("Error Processing Source Content", err) + return newSystemError("Error Processing Source Content", err) } for _, p := range site.Pages { @@ -84,5 +92,7 @@ posted in the future.`, } + return nil + }, } diff --git a/commands/list_config.go b/commands/list_config.go index 9520fdbc9..d71d04a67 100644 --- a/commands/list_config.go +++ b/commands/list_config.go @@ -25,8 +25,11 @@ var config = &cobra.Command{ Use: "config", Short: "Print the site configuration", Long: `Print the site configuration, both default and custom settings.`, - Run: func(cmd *cobra.Command, args []string) { - InitializeConfig() + RunE: func(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } + allSettings := viper.AllSettings() var separator string @@ -49,5 +52,7 @@ var config = &cobra.Command{ fmt.Printf("%s%s%+v\n", k, separator, allSettings[k]) } } + + return nil }, } diff --git a/commands/new.go b/commands/new.go index f2c362ac3..579d12a52 100644 --- a/commands/new.go +++ b/commands/new.go @@ -55,7 +55,7 @@ You can also specify the kind with ` + "`-k KIND`" + `. If archetypes are provided in your theme or site, they will be used.`, - Run: NewContent, + RunE: NewContent, } var newSiteCmd = &cobra.Command{ @@ -64,7 +64,7 @@ var newSiteCmd = &cobra.Command{ Long: `Create a new site in the provided directory. The new site will have the correct structure, but no content or theme yet. Use ` + "`hugo new [contentPath]`" + ` to create new content.`, - Run: NewSite, + RunE: NewSite, } var newThemeCmd = &cobra.Command{ @@ -74,20 +74,21 @@ var newThemeCmd = &cobra.Command{ New theme is a skeleton. Please add content to the touched files. Add your name to the copyright line in the license and adjust the theme.toml file as you see fit.`, - Run: NewTheme, + RunE: NewTheme, } // NewContent adds new content to a Hugo site. -func NewContent(cmd *cobra.Command, args []string) { - InitializeConfig() +func NewContent(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } if cmd.Flags().Lookup("format").Changed { viper.Set("MetaDataFormat", configFormat) } if len(args) < 1 { - cmd.Usage() - jww.FATAL.Fatalln("path needs to be provided") + return newUserError("path needs to be provided") } createpath := args[0] @@ -100,10 +101,8 @@ func NewContent(cmd *cobra.Command, args []string) { kind = contentType } - err := create.NewContent(kind, createpath) - if err != nil { - jww.ERROR.Println(err) - } + return create.NewContent(kind, createpath) + } func doNewSite(basepath string, force bool) error { @@ -146,32 +145,31 @@ func doNewSite(basepath string, force bool) error { } // NewSite creates a new hugo site and initializes a structured Hugo directory. -func NewSite(cmd *cobra.Command, args []string) { +func NewSite(cmd *cobra.Command, args []string) error { if len(args) < 1 { - cmd.Usage() - jww.FATAL.Fatalln("path needs to be provided") + return newUserError("path needs to be provided") } createpath, err := filepath.Abs(filepath.Clean(args[0])) if err != nil { - cmd.Usage() - jww.FATAL.Fatalln(err) + return newUserError(err) } forceNew, _ := cmd.Flags().GetBool("force") - if err := doNewSite(createpath, forceNew); err != nil { - cmd.Usage() - jww.FATAL.Fatalln(err) - } + + return doNewSite(createpath, forceNew) + } // NewTheme creates a new Hugo theme. -func NewTheme(cmd *cobra.Command, args []string) { - InitializeConfig() +func NewTheme(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } if len(args) < 1 { - cmd.Usage() - jww.FATAL.Fatalln("theme name needs to be provided") + + return newUserError("theme name needs to be provided") } createpath := helpers.AbsPathify(filepath.Join("themes", args[0])) @@ -229,10 +227,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), hugofs.SourceFs) if err != nil { - jww.FATAL.Fatalln(err) + return nil } createThemeMD(createpath) + + return nil } func mkdir(x ...string) { diff --git a/commands/server.go b/commands/server.go index 8d69304c3..378637b6c 100644 --- a/commands/server.go +++ b/commands/server.go @@ -57,7 +57,7 @@ By default hugo will also watch your files for any changes you make and 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.`, - //Run: server, + //RunE: server, } type filesOnlyFs struct { @@ -90,10 +90,10 @@ func init() { serverCmd.Flags().BoolVarP(&NoTimes, "noTimes", "", false, "Don't sync modification time of files") serverCmd.Flags().String("memstats", "", "log memory usage to this file") serverCmd.Flags().Int("meminterval", 100, "interval to poll memory usage (requires --memstats)") - serverCmd.Run = server + serverCmd.RunE = server } -func server(cmd *cobra.Command, args []string) { +func server(cmd *cobra.Command, args []string) error { InitializeConfig() if cmd.Flags().Lookup("disableLiveReload").Changed { @@ -116,8 +116,7 @@ func server(cmd *cobra.Command, args []string) { jww.ERROR.Println("port", serverPort, "already in use, attempting to use an available port") sp, err := helpers.FindAvailablePort() if err != nil { - jww.ERROR.Println("Unable to find alternative port to use") - jww.ERROR.Fatalln(err) + return newSystemError("Unable to find alternative port to use:", err) } serverPort = sp.Port } @@ -126,7 +125,7 @@ func server(cmd *cobra.Command, args []string) { BaseURL, err := fixURL(BaseURL) if err != nil { - jww.ERROR.Fatal(err) + return err } viper.Set("BaseURL", BaseURL) @@ -146,7 +145,9 @@ func server(cmd *cobra.Command, args []string) { viper.Set("PublishDir", "/") } - build(serverWatch) + if err := build(serverWatch); err != nil { + return err + } // Watch runs its own server as part of the routine if serverWatch { @@ -160,12 +161,15 @@ func server(cmd *cobra.Command, args []string) { jww.FEEDBACK.Printf("Watching for changes in %s/{%s}\n", baseWatchDir, rootWatchDirs) err := NewWatcher(serverPort) + if err != nil { - fmt.Println(err) + return err } } serve(serverPort) + + return nil } func serve(port int) { diff --git a/commands/undraft.go b/commands/undraft.go index 007729356..89b56c95e 100644 --- a/commands/undraft.go +++ b/commands/undraft.go @@ -20,7 +20,6 @@ import ( "github.com/spf13/cobra" "github.com/spf13/hugo/parser" - jww "github.com/spf13/jwalterweatherman" ) var undraftCmd = &cobra.Command{ @@ -29,53 +28,50 @@ var undraftCmd = &cobra.Command{ Long: `Undraft changes the content's draft status from 'True' to 'False' and updates the date to the current date and time. If the content's draft status is 'False', nothing is done.`, - Run: Undraft, + RunE: Undraft, } // Publish publishes the specified content by setting its draft status // to false and setting its publish date to now. If the specified content is // not a draft, it will log an error. -func Undraft(cmd *cobra.Command, args []string) { - InitializeConfig() +func Undraft(cmd *cobra.Command, args []string) error { + if err := InitializeConfig(); err != nil { + return err + } if len(args) < 1 { - cmd.Usage() - jww.FATAL.Fatalln("a piece of content needs to be specified") + return newUserError("a piece of content needs to be specified") } location := args[0] // open the file f, err := os.Open(location) if err != nil { - jww.ERROR.Print(err) - return + return err } // get the page from file p, err := parser.ReadFrom(f) f.Close() if err != nil { - jww.ERROR.Print(err) - return + return err } w, err := undraftContent(p) if err != nil { - jww.ERROR.Printf("an error occurred while undrafting %q: %s", location, err) - return + return newSystemError("an error occurred while undrafting %q: %s", location, err) } f, err = os.OpenFile(location, os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { - jww.ERROR.Printf("%q not be undrafted due to error opening file to save changes: %q\n", location, err) - return + return newSystemError("%q not be undrafted due to error opening file to save changes: %q\n", location, err) } defer f.Close() _, err = w.WriteTo(f) if err != nil { - jww.ERROR.Printf("%q not be undrafted due to save error: %q\n", location, err) + return newSystemError("%q not be undrafted due to save error: %q\n", location, err) } - return + return nil } // undraftContent: if the content is a draft, change its draft status to diff --git a/commands/version.go b/commands/version.go index f775f2e33..56c134bc5 100644 --- a/commands/version.go +++ b/commands/version.go @@ -32,7 +32,7 @@ var version = &cobra.Command{ Use: "version", Short: "Print the version number of Hugo", Long: `All software has versions. This is Hugo's.`, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if hugolib.BuildDate == "" { setBuildDate() // set the build date from executable's mdate } else { @@ -43,6 +43,8 @@ var version = &cobra.Command{ } else { fmt.Printf("Hugo Static Site Generator v%s-%s BuildDate: %s\n", helpers.HugoVersion(), strings.ToUpper(hugolib.CommitHash), hugolib.BuildDate) } + + return nil }, } diff --git a/hugolib/site.go b/hugolib/site.go index a8f0599bb..8cdfa44f2 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -254,9 +254,11 @@ func (s *Site) Build() (err error) { return nil } -func (s *Site) Analyze() { - s.Process() - s.ShowPlan(os.Stdout) +func (s *Site) Analyze() error { + if err := s.Process(); err != nil { + return err + } + return s.ShowPlan(os.Stdout) } func (s *Site) prepTemplates() {