summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Scoble <joel.scoble@outlook.com>2015-03-15 17:32:41 -0500
committerspf13 <steve.francia@gmail.com>2015-05-08 22:18:51 -0400
commitb4871787f02d6660da8bc82b951178dc3964d9a9 (patch)
treea58f58619e4d7b185d3f6752ba82fe1140761163
parent563a6302a0a27f1b8412d4ab621e336f83159727 (diff)
add undraft command
-rw-r--r--commands/hugo.go1
-rw-r--r--commands/undraft.go157
-rw-r--r--commands/undraft_test.go72
-rw-r--r--parser/page.go4
4 files changed, 232 insertions, 2 deletions
diff --git a/commands/hugo.go b/commands/hugo.go
index 0ad49bbe5..1f3e63918 100644
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -75,6 +75,7 @@ func AddCommands() {
HugoCmd.AddCommand(convertCmd)
HugoCmd.AddCommand(newCmd)
HugoCmd.AddCommand(listCmd)
+ HugoCmd.AddCommand(undraftCmd)
}
//Initializes flags
diff --git a/commands/undraft.go b/commands/undraft.go
new file mode 100644
index 000000000..4dbdf45c9
--- /dev/null
+++ b/commands/undraft.go
@@ -0,0 +1,157 @@
+// Copyright © 2013 Steve Francia <spf@spf13.com>.
+//
+// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 (
+ "bytes"
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/spf13/cobra"
+ "github.com/spf13/hugo/parser"
+ jww "github.com/spf13/jwalterweatherman"
+)
+
+var undraftCmd = &cobra.Command{
+ Use: "undraft path/to/content",
+ Short: "Undraft changes the content's draft status from 'True' to 'False'",
+ 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,
+}
+
+// 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()
+
+ if len(args) < 1 {
+ cmd.Usage()
+ jww.FATAL.Fatalln("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
+ }
+
+ // get the page from file
+ p, err := parser.ReadFrom(f)
+ f.Close()
+ if err != nil {
+ jww.ERROR.Print(err)
+ return
+ }
+
+ w, err := undraftContent(p)
+ if err != nil {
+ jww.ERROR.Printf("an error occurred while undrafting %q: %s", location, err)
+ return
+ }
+
+ 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
+ }
+ 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
+}
+
+// undraftContent: if the content is a draft, change it's draft status to
+// 'false' and set the date to time.Now(). If the draft status is already
+// 'false', don't do anything.
+func undraftContent(p parser.Page) (bytes.Buffer, error) {
+ var buff bytes.Buffer
+ // get the metadata; easiest way to see if it's a draft
+ meta, err := p.Metadata()
+ if err != nil {
+ return buff, err
+ }
+ // since the metadata was obtainable, we can also get the key/value separator for
+ // Front Matter
+ fm := p.FrontMatter()
+ if fm == nil {
+ err := fmt.Errorf("Front Matter was found, nothing was finalized")
+ return buff, err
+ }
+
+ var isDraft, gotDate bool
+ var date string
+L:
+ for k, v := range meta.(map[string]interface{}) {
+ switch k {
+ case "draft":
+ if !v.(bool) {
+ return buff, fmt.Errorf("not a Draft: nothing was done")
+ }
+ isDraft = true
+ if gotDate {
+ break L
+ }
+ case "date":
+ date = v.(string) // capture the value to make replacement easier
+ gotDate = true
+ if isDraft {
+ break L
+ }
+ }
+ }
+
+ // if draft wasn't found in FrontMatter, it isn't a draft.
+ if !isDraft {
+ return buff, fmt.Errorf("not a Draft: nothing was done")
+ }
+
+ // get the front matter as bytes and split it into lines
+ var lineEnding []byte
+ fmLines := bytes.Split(fm, parser.UnixEnding)
+ if len(fmLines) == 1 { // if the result is only 1 element, try to split on dos line endings
+ fmLines = bytes.Split(fm, parser.DosEnding)
+ if len(fmLines) == 1 {
+ return buff, fmt.Errorf("unable to split FrontMatter into lines")
+ }
+ lineEnding = append(lineEnding, parser.DosEnding...)
+ } else {
+ lineEnding = append(lineEnding, parser.UnixEnding...)
+ }
+
+ // Write the front matter lines to the buffer, replacing as necessary
+ for _, v := range fmLines {
+ pos := bytes.Index(v, []byte("draft"))
+ if pos != -1 {
+ v = bytes.Replace(v, []byte("true"), []byte("false"), 1)
+ goto write
+ }
+ pos = bytes.Index(v, []byte("date"))
+ if pos != -1 { // if date field wasn't found, add it
+ v = bytes.Replace(v, []byte(date), []byte(time.Now().Format(time.RFC3339)), 1)
+ }
+ write:
+ buff.Write(v)
+ buff.Write(lineEnding)
+ }
+
+ // append the actual content
+ buff.Write([]byte(p.Content()))
+
+ return buff, nil
+}
diff --git a/commands/undraft_test.go b/commands/undraft_test.go
new file mode 100644
index 000000000..e0a654f3a
--- /dev/null
+++ b/commands/undraft_test.go
@@ -0,0 +1,72 @@
+package commands
+
+// TODO Support Mac Encoding (\r)
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/spf13/hugo/parser"
+)
+
+var (
+ jsonFM = "{\n \"date\": \"12-04-06\",\n \"title\": \"test json\"\n}"
+ jsonDraftFM = "{\n \"draft\": true,\n \"date\": \"12-04-06\",\n \"title\":\"test json\"\n}"
+ tomlFM = "+++\n date= \"12-04-06\"\n title= \"test toml\"\n+++"
+ tomlDraftFM = "+++\n draft= true\n date= \"12-04-06\"\n title=\"test toml\"\n+++"
+ yamlFM = "---\n date: \"12-04-06\"\n title: \"test yaml\"\n---"
+ yamlDraftFM = "---\n draft: true\n date: \"12-04-06\"\n title: \"test yaml\"\n---"
+)
+
+func TestUndraftContent(t *testing.T) {
+ tests := []struct {
+ fm string
+ expectedErr string
+ }{
+ {jsonFM, "not a Draft: nothing was done"},
+ {jsonDraftFM, ""},
+ {tomlFM, "not a Draft: nothing was done"},
+ {tomlDraftFM, ""},
+ {yamlFM, "not a Draft: nothing was done"},
+ {yamlDraftFM, ""},
+ }
+
+ for _, test := range tests {
+ r := bytes.NewReader([]byte(test.fm))
+ p, _ := parser.ReadFrom(r)
+ res, err := undraftContent(p)
+ if test.expectedErr != "" {
+ if err == nil {
+ t.Error("Expected error, got none")
+ continue
+ }
+ if err.Error() != test.expectedErr {
+ t.Errorf("Expected %q, got %q", test.expectedErr, err)
+ continue
+ }
+ } else {
+ r = bytes.NewReader(res.Bytes())
+ p, _ = parser.ReadFrom(r)
+ meta, err := p.Metadata()
+ if err != nil {
+ t.Errorf("unexpected error %q", err)
+ continue
+ }
+ for k, v := range meta.(map[string]interface{}) {
+ if k == "draft" {
+ if v.(bool) {
+ t.Errorf("Expected %q to be \"false\", got \"true\"", k)
+ continue
+ }
+ }
+ if k == "date" {
+ if !strings.HasPrefix(v.(string), time.Now().Format("2006-01-02")) {
+ t.Errorf("Expected %v to start with %v", v.(string), time.Now().Format("2006-01-02"))
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/parser/page.go b/parser/page.go
index 65a62a566..77d40a602 100644
--- a/parser/page.go
+++ b/parser/page.go
@@ -30,8 +30,8 @@ var (
[]byte(JSON_LEAD),
}
- unixEnding = []byte("\n")
- dosEnding = []byte("\r\n")
+ UnixEnding = []byte("\n")
+ DosEnding = []byte("\r\n")
)
type FrontMatter []byte