Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API for external applications #1860

Closed
wants to merge 16 commits into from
28 changes: 28 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2016

//
// 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 api

import (
"github.com/spf13/hugo/commands"
"github.com/spf13/viper"
)

func Run(flags []string) {
commands.Execute(flags)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't hugoCmd.ExecuteC() do the trick? Note the C at the end, then you can return an error to the client in case of errors. You would probably have to duplicate parts of commands.Execute -- but it would make a slightly better API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bep that would be a good idea, but to do so I would have to export HugoCmd, wouldn't I?

}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of my thoughts with an API was to limit it somehow to what the external tools needs. I know this is hard with the current setup, but if you limit it to the hugoCmd (for starters), you could name this func Build() or something. Then it also would be possible to create a more natural API than the CLI flags.


func Reset() {
commands.ClearSite()
viper.Reset()
}
4 changes: 2 additions & 2 deletions commands/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func benchmark(cmd *cobra.Command, args []string) error {
return err
}
for i := 0; i < benchmarkTimes; i++ {
MainSite = nil
mainSite = nil
_ = buildSite()
}
pprof.WriteHeapProfile(f)
Expand All @@ -76,7 +76,7 @@ func benchmark(cmd *cobra.Command, args []string) error {
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
for i := 0; i < benchmarkTimes; i++ {
MainSite = nil
mainSite = nil
_ = buildSite()
}
}
Expand Down
93 changes: 51 additions & 42 deletions commands/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import (
"gopkg.in/fsnotify.v1"
)

var MainSite *hugolib.Site
var mainSite *hugolib.Site

// userError is an error used to signal different error situations in command handling.
type commandError struct {
Expand Down Expand Up @@ -91,9 +91,9 @@ func isUserError(err error) bool {
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{
// hugoCmd is Hugo's root command.
// Every other command attached to hugoCmd is a child command to it.
var hugoCmd = &cobra.Command{
Use: "hugo",
Short: "hugo builds your site",
Long: `hugo is the main command, used to build your Hugo site.
Expand Down Expand Up @@ -150,15 +150,26 @@ var (
source string
)

// Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
func Execute() {
HugoCmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)
// ClearSite sets mainSite to nil
func ClearSite() {
mainSite = nil
}

// Execute adds all child commands to the root command hugoCmd and sets flags appropriately.
func Execute(flags []string) {
hugoCmd.SetGlobalNormalizationFunc(helpers.NormalizeHugoFlags)

HugoCmd.SilenceUsage = true
hugoCmd.SilenceUsage = true

AddCommands()

if c, err := HugoCmd.ExecuteC(); err != nil {
if flags != nil {
if err := hugoCmd.ParseFlags(flags); err != nil {
os.Exit(-1)
}
}

if c, err := hugoCmd.ExecuteC(); err != nil {
if isUserError(err) {
c.Println("")
c.Println(c.UsageString())
Expand All @@ -168,20 +179,20 @@ func Execute() {
}
}

// AddCommands adds child commands to the root command HugoCmd.
// AddCommands adds child commands to the root command hugoCmd.
func AddCommands() {
HugoCmd.AddCommand(serverCmd)
HugoCmd.AddCommand(versionCmd)
HugoCmd.AddCommand(configCmd)
HugoCmd.AddCommand(checkCmd)
HugoCmd.AddCommand(benchmarkCmd)
HugoCmd.AddCommand(convertCmd)
HugoCmd.AddCommand(newCmd)
HugoCmd.AddCommand(listCmd)
HugoCmd.AddCommand(undraftCmd)
HugoCmd.AddCommand(importCmd)

HugoCmd.AddCommand(genCmd)
hugoCmd.AddCommand(serverCmd)
hugoCmd.AddCommand(versionCmd)
hugoCmd.AddCommand(configCmd)
hugoCmd.AddCommand(checkCmd)
hugoCmd.AddCommand(benchmarkCmd)
hugoCmd.AddCommand(convertCmd)
hugoCmd.AddCommand(newCmd)
hugoCmd.AddCommand(listCmd)
hugoCmd.AddCommand(undraftCmd)
hugoCmd.AddCommand(importCmd)

hugoCmd.AddCommand(genCmd)
genCmd.AddCommand(genautocompleteCmd)
genCmd.AddCommand(gendocCmd)
genCmd.AddCommand(genmanCmd)
Expand Down Expand Up @@ -241,19 +252,19 @@ func initBenchmarkBuildingFlags(cmd *cobra.Command) {

// init initializes flags.
func init() {
HugoCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose 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")
hugoCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose 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")

initHugoBuilderFlags(HugoCmd)
initBenchmarkBuildingFlags(HugoCmd)
initHugoBuilderFlags(hugoCmd)
initBenchmarkBuildingFlags(hugoCmd)

HugoCmd.Flags().BoolVarP(&buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
hugoCmdV = HugoCmd
hugoCmd.Flags().BoolVarP(&buildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
hugoCmdV = hugoCmd

// Set bash-completion
HugoCmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
hugoCmd.PersistentFlags().SetAnnotation("logFile", cobra.BashCompFilenameExt, []string{})
}

func LoadDefaultSettings() {
Expand Down Expand Up @@ -318,9 +329,9 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
if err != nil {
if _, ok := err.(viper.ConfigParseError); ok {
return newSystemError(err)
} else {
return newSystemErrorF("Unable to locate Config file. Perhaps you need to create a new site.\n Run `hugo help new` for details. (%s)\n", err)
}

return newSystemErrorF("Unable to locate Config file. Perhaps you need to create a new site.\n Run `hugo help new` for details. (%s)\n", err)
}

viper.RegisterAlias("indexes", "taxonomies")
Expand Down Expand Up @@ -467,8 +478,6 @@ func watchConfig() {
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
// Force a full rebuild
MainSite = nil
utils.CheckErr(buildSite(true))
if !viper.GetBool("DisableLiveReload") {
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
Expand Down Expand Up @@ -652,29 +661,29 @@ func getDirList() []string {
func buildSite(watching ...bool) (err error) {
fmt.Println("Started building site")
startTime := time.Now()
if MainSite == nil {
MainSite = new(hugolib.Site)
if mainSite == nil {
mainSite = new(hugolib.Site)
}
if len(watching) > 0 && watching[0] {
MainSite.RunMode.Watching = true
mainSite.RunMode.Watching = true
}
err = MainSite.Build()
err = mainSite.Build()
if err != nil {
return err
}
MainSite.Stats()
mainSite.Stats()
jww.FEEDBACK.Printf("in %v ms\n", int(1000*time.Since(startTime).Seconds()))

return nil
}

func rebuildSite(events []fsnotify.Event) error {
startTime := time.Now()
err := MainSite.ReBuild(events)
err := mainSite.ReBuild(events)
if err != nil {
return err
}
MainSite.Stats()
mainSite.Stats()
jww.FEEDBACK.Printf("in %v ms\n", int(1000*time.Since(startTime).Seconds()))

return nil
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ import (

func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
commands.Execute()
commands.Execute(nil)
}