shithub: hugo

Download patch

ref: 2aab6dee850517533683504a6158e0ef0a3ffc57
parent: f3775877c61c11ab7c8fd1fc3e15470bf5da4820
author: Bjørn Erik Pedersen <[email protected]>
date: Fri Apr 13 04:42:29 EDT 2018

commands: Fix handling of persistent CLI flags

See #4607

--- a/commands/benchmark.go
+++ b/commands/benchmark.go
@@ -31,7 +31,7 @@
 	*baseBuilderCmd
 }
 
-func newBenchmarkCmd() *benchmarkCmd {
+func (b *commandsBuilder) newBenchmarkCmd() *benchmarkCmd {
 	cmd := &cobra.Command{
 		Use:   "benchmark",
 		Short: "Benchmark Hugo by building a site a number of times.",
@@ -39,7 +39,7 @@
 creating a benchmark.`,
 	}
 
-	c := &benchmarkCmd{baseBuilderCmd: newBuilderCmd(cmd)}
+	c := &benchmarkCmd{baseBuilderCmd: b.newBuilderCmd(cmd)}
 
 	cmd.Flags().StringVar(&c.cpuProfileFile, "cpuprofile", "", "path/filename for the CPU profile file")
 	cmd.Flags().StringVar(&c.memProfileFile, "memprofile", "", "path/filename for the memory profile file")
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -21,23 +21,29 @@
 	"github.com/spf13/nitro"
 )
 
-// newHugoCompleteCmd builds the complete set of Hugo CLI commands.
-func newHugoCompleteCmd() *hugoCmd {
-	h := newHugoCmd()
-	addAllCommands(h.getCommand())
-	return h
+type commandsBuilder struct {
+	hugoBuilderCommon
+
+	commands []cmder
 }
 
-// addAllCommands adds child commands to the root command HugoCmd.
-func addAllCommands(root *cobra.Command) {
-	addCommands(
-		root,
-		newServerCmd(),
+func newCommandsBuilder() *commandsBuilder {
+	return &commandsBuilder{}
+}
+
+func (b *commandsBuilder) addCommands(commands ...cmder) *commandsBuilder {
+	b.commands = append(b.commands, commands...)
+	return b
+}
+
+func (b *commandsBuilder) addAll() *commandsBuilder {
+	b.addCommands(
+		b.newServerCmd(),
 		newVersionCmd(),
 		newEnvCmd(),
 		newConfigCmd(),
 		newCheckCmd(),
-		newBenchmarkCmd(),
+		b.newBenchmarkCmd(),
 		newConvertCmd(),
 		newNewCmd(),
 		newListCmd(),
@@ -44,8 +50,16 @@
 		newImportCmd(),
 		newGenCmd(),
 	)
+
+	return b
 }
 
+func (b *commandsBuilder) build() *hugoCmd {
+	h := b.newHugoCmd()
+	addCommands(h.getCommand(), b.commands...)
+	return h
+}
+
 func addCommands(root *cobra.Command, commands ...cmder) {
 	for _, command := range commands {
 		root.AddCommand(command.getCommand())
@@ -56,11 +70,21 @@
 	cmd *cobra.Command
 }
 
+var _ commandsBuilderGetter = (*baseBuilderCmd)(nil)
+
+// Used in tests.
+type commandsBuilderGetter interface {
+	getCmmandsBuilder() *commandsBuilder
+}
 type baseBuilderCmd struct {
-	hugoBuilderCommon
 	*baseCmd
+	*commandsBuilder
 }
 
+func (b *baseBuilderCmd) getCmmandsBuilder() *commandsBuilder {
+	return b.commandsBuilder
+}
+
 func (c *baseCmd) getCommand() *cobra.Command {
 	return c.cmd
 }
@@ -69,8 +93,8 @@
 	return &baseCmd{cmd: cmd}
 }
 
-func newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
-	bcmd := &baseBuilderCmd{baseCmd: &baseCmd{cmd: cmd}}
+func (b *commandsBuilder) newBuilderCmd(cmd *cobra.Command) *baseBuilderCmd {
+	bcmd := &baseBuilderCmd{commandsBuilder: b, baseCmd: &baseCmd{cmd: cmd}}
 	bcmd.hugoBuilderCommon.handleFlags(cmd)
 	return bcmd
 }
@@ -86,10 +110,10 @@
 	c *commandeer
 }
 
-func newHugoCmd() *hugoCmd {
+func (b *commandsBuilder) newHugoCmd() *hugoCmd {
 	cc := &hugoCmd{}
 
-	cc.baseBuilderCmd = newBuilderCmd(&cobra.Command{
+	cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
 		Use:   "hugo",
 		Short: "hugo builds your site",
 		Long: `hugo is the main command, used to build your Hugo site.
--- a/commands/commands_test.go
+++ b/commands/commands_test.go
@@ -20,6 +20,8 @@
 	"path/filepath"
 	"testing"
 
+	"github.com/spf13/cobra"
+
 	"github.com/stretchr/testify/require"
 )
 
@@ -41,8 +43,45 @@
 	assert.True(len(result.Sites[0].RegularPages) == 1)
 }
 
-func TestCommands(t *testing.T) {
+func TestCommandsPersistentFlags(t *testing.T) {
+	assert := require.New(t)
 
+	noOpRunE := func(cmd *cobra.Command, args []string) error {
+		return nil
+	}
+
+	tests := []struct {
+		args  []string
+		check func(command []cmder)
+	}{{[]string{"server", "--config=myconfig.toml", "-b=https://example.com/b/", "--source=mysource"}, func(commands []cmder) {
+		for _, command := range commands {
+			if b, ok := command.(commandsBuilderGetter); ok {
+				v := b.getCmmandsBuilder().hugoBuilderCommon
+				assert.Equal("myconfig.toml", v.cfgFile)
+				assert.Equal("mysource", v.source)
+				assert.Equal("https://example.com/b/", v.baseURL)
+			}
+		}
+	}}}
+
+	for _, test := range tests {
+		b := newCommandsBuilder()
+		root := b.addAll().build()
+
+		for _, c := range b.commands {
+			// We are only intereseted in the flag handling here.
+			c.getCommand().RunE = noOpRunE
+		}
+		rootCmd := root.getCommand()
+		rootCmd.SetArgs(test.args)
+		assert.NoError(rootCmd.Execute())
+		test.check(b.commands)
+	}
+
+}
+
+func TestCommandsExecute(t *testing.T) {
+
 	assert := require.New(t)
 
 	dir, err := createSimpleTestSite(t)
@@ -90,7 +129,7 @@
 
 	for _, test := range tests {
 
-		hugoCmd := newHugoCompleteCmd().getCommand()
+		hugoCmd := newCommandsBuilder().addAll().build().getCommand()
 		test.flags = append(test.flags, "--quiet")
 		hugoCmd.SetArgs(append(test.commands, test.flags...))
 
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -70,7 +70,7 @@
 // Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
 // The args are usually filled with os.Args[1:].
 func Execute(args []string) Response {
-	hugoCmd := newHugoCompleteCmd()
+	hugoCmd := newCommandsBuilder().addAll().build()
 	cmd := hugoCmd.getCommand()
 	cmd.SetArgs(args)
 
--- a/commands/server.go
+++ b/commands/server.go
@@ -57,14 +57,14 @@
 	*baseBuilderCmd
 }
 
-func newServerCmd() *serverCmd {
-	return newServerCmdSignaled(nil)
+func (b *commandsBuilder) newServerCmd() *serverCmd {
+	return b.newServerCmdSignaled(nil)
 }
 
-func newServerCmdSignaled(stop <-chan bool) *serverCmd {
+func (b *commandsBuilder) newServerCmdSignaled(stop <-chan bool) *serverCmd {
 	cc := &serverCmd{stop: stop}
 
-	cc.baseBuilderCmd = newBuilderCmd(&cobra.Command{
+	cc.baseBuilderCmd = b.newBuilderCmd(&cobra.Command{
 		Use:     "server",
 		Aliases: []string{"serve"},
 		Short:   "A high performance webserver",
@@ -463,7 +463,8 @@
 }
 
 func memStats() error {
-	sc := newServerCmd().getCommand()
+	b := newCommandsBuilder()
+	sc := b.newServerCmd().getCommand()
 	memstats := sc.Flags().Lookup("memstats").Value.String()
 	if memstats != "" {
 		interval, err := time.ParseDuration(sc.Flags().Lookup("meminterval").Value.String())
--- a/commands/server_test.go
+++ b/commands/server_test.go
@@ -40,7 +40,8 @@
 
 	stop := make(chan bool)
 
-	scmd := newServerCmdSignaled(stop)
+	b := newCommandsBuilder()
+	scmd := b.newServerCmdSignaled(stop)
 
 	cmd := scmd.getCommand()
 	cmd.SetArgs([]string{"-s=" + dir, fmt.Sprintf("-p=%d", port)})
@@ -90,7 +91,8 @@
 	}
 
 	for i, test := range tests {
-		s := newServerCmd()
+		b := newCommandsBuilder()
+		s := b.newServerCmd()
 		v := viper.New()
 		baseURL := test.CLIBaseURL
 		v.Set("baseURL", test.CfgBaseURL)