mirror of
				https://github.com/gohugoio/hugo.git
				synced 2024-05-11 05:54:58 +00:00 
			
		
		
		
	add undraft command
This commit is contained in:
		@@ -75,6 +75,7 @@ func AddCommands() {
 | 
			
		||||
	HugoCmd.AddCommand(convertCmd)
 | 
			
		||||
	HugoCmd.AddCommand(newCmd)
 | 
			
		||||
	HugoCmd.AddCommand(listCmd)
 | 
			
		||||
	HugoCmd.AddCommand(undraftCmd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Initializes flags
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								commands/undraft.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								commands/undraft.go
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								commands/undraft_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								commands/undraft_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -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"))
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user