commands: Create new 'hugo list all' command

New:
- command `hugo list all`, return all posts meta in csv format

Refactoring:
- move common parts in commands/list.go to function `buildSites`
- change way to detect path to content

See #5904
This commit is contained in:
Ruslan Nasonov 2019-05-04 21:21:21 +07:00 committed by Bjørn Erik Pedersen
parent 2278b0eb02
commit 5b4b8bb3c1
2 changed files with 164 additions and 57 deletions

View file

@ -16,7 +16,8 @@ package commands
import ( import (
"encoding/csv" "encoding/csv"
"os" "os"
"path/filepath" "strconv"
"strings"
"time" "time"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
@ -32,6 +33,32 @@ type listCmd struct {
*baseCmd *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 { func newListCmd() *listCmd {
cc := &listCmd{} cc := &listCmd{}
@ -50,59 +77,30 @@ List requires a subcommand, e.g. ` + "`hugo list drafts`.",
Short: "List all drafts", Short: "List all drafts",
Long: `List all of the drafts in your content directory.`, Long: `List all of the drafts in your content directory.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error { sites, err := cc.buildSites(map[string]interface{}{"buildDrafts": true})
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)
if err != nil { if err != nil {
return newSystemError("Error creating sites", err) return newSystemError("Error building sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
} }
for _, p := range sites.Pages() { for _, p := range sites.Pages() {
if p.Draft() { 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 return nil
}, },
}, },
&cobra.Command{ &cobra.Command{
Use: "future", Use: "future",
Short: "List all posts dated in the future", Short: "List all posts dated in the future",
Long: `List all of the posts in your content directory which will be Long: `List all of the posts in your content directory which will be posted in the future.`,
posted in the future.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error { sites, err := cc.buildSites(map[string]interface{}{"buildFuture": true})
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)
if err != nil { if err != nil {
return newSystemError("Error creating sites", err) return newSystemError("Error building sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
} }
writer := csv.NewWriter(os.Stdout) writer := csv.NewWriter(os.Stdout)
@ -110,7 +108,10 @@ posted in the future.`,
for _, p := range sites.Pages() { for _, p := range sites.Pages() {
if resource.IsFuture(p) { 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 { if err != nil {
return newSystemError("Error writing future posts to stdout", err) return newSystemError("Error writing future posts to stdout", err)
} }
@ -118,32 +119,17 @@ posted in the future.`,
} }
return nil return nil
}, },
}, },
&cobra.Command{ &cobra.Command{
Use: "expired", Use: "expired",
Short: "List all posts already expired", Short: "List all posts already expired",
Long: `List all of the posts in your content directory which has already Long: `List all of the posts in your content directory which has already expired.`,
expired.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cfgInit := func(c *commandeer) error { sites, err := cc.buildSites(map[string]interface{}{"buildExpired": true})
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)
if err != nil { if err != nil {
return newSystemError("Error creating sites", err) return newSystemError("Error building sites", err)
}
if err := sites.Build(hugolib.BuildCfg{SkipRender: true}); err != nil {
return newSystemError("Error Processing Source Content", err)
} }
writer := csv.NewWriter(os.Stdout) writer := csv.NewWriter(os.Stdout)
@ -151,16 +137,67 @@ expired.`,
for _, p := range sites.Pages() { for _, p := range sites.Pages() {
if resource.IsExpired(p) { 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 { if err != nil {
return newSystemError("Error writing expired posts to stdout", err) return newSystemError("Error writing expired posts to stdout", err)
} }
} }
} }
return nil 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
}, },
}, },
) )

70
commands/list_test.go Normal file
View file

@ -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)
}