diff --git a/commands/list.go b/commands/list.go index bdf34663f..f233ce62c 100644 --- a/commands/list.go +++ b/commands/list.go @@ -16,7 +16,8 @@ package commands import ( "encoding/csv" "os" - "path/filepath" + "strconv" + "strings" "time" "github.com/gohugoio/hugo/hugolib" @@ -32,6 +33,32 @@ type listCmd struct { *baseCmd } +func (lc *listCmd) buildSites(config map[string]interface{}) (*hugolib.HugoSites, error) { + cfgInit := func(c *commandeer) error { + for key, value := range config { + c.Set(key, value) + } + return nil + } + + c, err := initializeConfig(true, false, &lc.hugoBuilderCommon, lc, cfgInit) + if err != nil { + return nil, err + } + + sites, err := hugolib.NewHugoSites(*c.DepsCfg) + + if err != nil { + return nil, newSystemError("Error creating sites", err) + } + + if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil { + return nil, newSystemError("Error Processing Source Content", err) + } + + return sites, nil +} + func newListCmd() *listCmd { cc := &listCmd{} @@ -50,59 +77,30 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.", Short: "List all drafts", Long: `List all of the drafts in your content directory.`, RunE: func(cmd *cobra.Command, args []string) error { - cfgInit := func(c *commandeer) error { - c.Set("buildDrafts", true) - return nil - } - c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit) - if err != nil { - return err - } - - sites, err := hugolib.NewHugoSites(*c.DepsCfg) + sites, err := cc.buildSites(map[string]interface{}{"buildDrafts": true}) if err != nil { - return newSystemError("Error creating sites", err) - } - - if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil { - return newSystemError("Error Processing Source Content", err) + return newSystemError("Error building sites", err) } for _, p := range sites.Pages() { if p.Draft() { - jww.FEEDBACK.Println(filepath.Join(p.File().Dir(), p.File().LogicalName())) + jww.FEEDBACK.Println(strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator))) } - } return nil - }, }, &cobra.Command{ Use: "future", 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.`, + Long: `List all of the posts in your content directory which will be posted in the future.`, RunE: func(cmd *cobra.Command, args []string) error { - cfgInit := func(c *commandeer) error { - c.Set("buildFuture", true) - return nil - } - c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit) - if err != nil { - return err - } - - sites, err := hugolib.NewHugoSites(*c.DepsCfg) + sites, err := cc.buildSites(map[string]interface{}{"buildFuture": true}) if err != nil { - return newSystemError("Error creating sites", err) - } - - if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil { - return newSystemError("Error Processing Source Content", err) + return newSystemError("Error building sites", err) } writer := csv.NewWriter(os.Stdout) @@ -110,7 +108,10 @@ posted in the future.`, for _, p := range sites.Pages() { if resource.IsFuture(p) { - err := writer.Write([]string{filepath.Join(p.File().Dir(), p.File().LogicalName()), p.PublishDate().Format(time.RFC3339)}) + err := writer.Write([]string{ + strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)), + p.PublishDate().Format(time.RFC3339), + }) if err != nil { return newSystemError("Error writing future posts to stdout", err) } @@ -118,32 +119,17 @@ posted in the future.`, } return nil - }, }, &cobra.Command{ Use: "expired", Short: "List all posts already expired", - Long: `List all of the posts in your content directory which has already -expired.`, + Long: `List all of the posts in your content directory which has already expired.`, RunE: func(cmd *cobra.Command, args []string) error { - cfgInit := func(c *commandeer) error { - c.Set("buildExpired", true) - return nil - } - c, err := initializeConfig(true, false, &cc.hugoBuilderCommon, cc, cfgInit) - if err != nil { - return err - } - - sites, err := hugolib.NewHugoSites(*c.DepsCfg) + sites, err := cc.buildSites(map[string]interface{}{"buildExpired": true}) if err != nil { - return newSystemError("Error creating sites", err) - } - - if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil { - return newSystemError("Error Processing Source Content", err) + return newSystemError("Error building sites", err) } writer := csv.NewWriter(os.Stdout) @@ -151,16 +137,67 @@ expired.`, for _, p := range sites.Pages() { if resource.IsExpired(p) { - err := writer.Write([]string{filepath.Join(p.File().Dir(), p.File().LogicalName()), p.ExpiryDate().Format(time.RFC3339)}) + err := writer.Write([]string{ + strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)), + p.ExpiryDate().Format(time.RFC3339), + }) if err != nil { return newSystemError("Error writing expired posts to stdout", err) } - } } return nil + }, + }, + &cobra.Command{ + Use: "all", + Short: "List all posts", + Long: `List all of the posts in your content directory, include drafts, future and expired pages.`, + RunE: func(cmd *cobra.Command, args []string) error { + sites, err := cc.buildSites(map[string]interface{}{ + "buildExpired": true, + "buildDrafts": true, + "buildFuture": true, + }) + if err != nil { + return newSystemError("Error building sites", err) + } + + writer := csv.NewWriter(os.Stdout) + defer writer.Flush() + + writer.Write([]string{ + "path", + "slug", + "title", + "date", + "expiryDate", + "publishDate", + "draft", + "permalink", + }) + for _, p := range sites.Pages() { + if !p.IsPage() { + continue + } + err := writer.Write([]string{ + strings.TrimPrefix(p.File().Filename(), sites.WorkingDir+string(os.PathSeparator)), + p.Slug(), + p.Title(), + p.Date().Format(time.RFC3339), + p.ExpiryDate().Format(time.RFC3339), + p.PublishDate().Format(time.RFC3339), + strconv.FormatBool(p.Draft()), + p.Permalink(), + }) + if err != nil { + return newSystemError("Error writing posts to stdout", err) + } + } + + return nil }, }, ) diff --git a/commands/list_test.go b/commands/list_test.go new file mode 100644 index 000000000..f2ce70010 --- /dev/null +++ b/commands/list_test.go @@ -0,0 +1,70 @@ +package commands + +import ( + "bytes" + "encoding/csv" + "io" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +func captureStdout(f func() (*cobra.Command, error)) (string, error) { + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + _, err := f() + + if err != nil { + return "", err + } + + w.Close() + os.Stdout = old + + var buf bytes.Buffer + io.Copy(&buf, r) + return buf.String(), nil +} + +func TestListAll(t *testing.T) { + assert := require.New(t) + dir, err := createSimpleTestSite(t, testSiteConfig{}) + + assert.NoError(err) + + hugoCmd := newCommandsBuilder().addAll().build() + cmd := hugoCmd.getCommand() + + defer func() { + os.RemoveAll(dir) + }() + + cmd.SetArgs([]string{"-s=" + dir, "list", "all"}) + + out, err := captureStdout(cmd.ExecuteC) + assert.NoError(err) + + r := csv.NewReader(strings.NewReader(out)) + + header, err := r.Read() + assert.NoError(err) + + assert.Equal([]string{ + "path", "slug", "title", + "date", "expiryDate", "publishDate", + "draft", "permalink", + }, header) + + record, err := r.Read() + assert.Equal([]string{ + filepath.Join("content", "p1.md"), "", "P1", + "0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z", "0001-01-01T00:00:00Z", + "false", "https://example.org/p1/", + }, record) +}