mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
command: Remove undraft command
According to @bep, it is easier to undraft content by editing manually the frontmatter of said content by setting the draft flag to `false`, or removing it completely, than to rely on the undraft command which is a source of many bugs. Fixes #4353
This commit is contained in:
parent
b6f3f087aa
commit
2fa70c9344
7 changed files with 2 additions and 296 deletions
|
@ -208,7 +208,6 @@ func AddCommands() {
|
|||
HugoCmd.AddCommand(convertCmd)
|
||||
HugoCmd.AddCommand(newCmd)
|
||||
HugoCmd.AddCommand(listCmd)
|
||||
HugoCmd.AddCommand(undraftCmd)
|
||||
HugoCmd.AddCommand(importCmd)
|
||||
|
||||
HugoCmd.AddCommand(genCmd)
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
// Copyright 2015 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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"
|
||||
"errors"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/hugo/parser"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var undraftCmd = &cobra.Command{
|
||||
Use: "undraft path/to/content",
|
||||
Short: "Undraft resets the content's draft status",
|
||||
Long: `Undraft resets the content's draft status
|
||||
and updates the date to the current date and time.
|
||||
If the content's draft status is 'False', nothing is done.`,
|
||||
RunE: Undraft,
|
||||
}
|
||||
|
||||
// Undraft 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) error {
|
||||
c, err := InitializeConfig(false, nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) < 1 {
|
||||
return newUserError("a piece of content needs to be specified")
|
||||
}
|
||||
|
||||
cfg := c.DepsCfg
|
||||
|
||||
location := args[0]
|
||||
// open the file
|
||||
f, err := cfg.Fs.Source.Open(location)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the page from file
|
||||
p, err := parser.ReadFrom(f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w, err := undraftContent(p)
|
||||
if err != nil {
|
||||
return newSystemErrorF("an error occurred while undrafting %q: %s", location, err)
|
||||
}
|
||||
|
||||
f, err = cfg.Fs.Source.OpenFile(location, os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return newSystemErrorF("%q not be undrafted due to error opening file to save changes: %q\n", location, err)
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = w.WriteTo(f)
|
||||
if err != nil {
|
||||
return newSystemErrorF("%q not be undrafted due to save error: %q\n", location, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// undraftContent: if the content is a draft, change its 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 {
|
||||
return buff, errors.New("Front Matter was found, nothing was finalized")
|
||||
}
|
||||
|
||||
var isDraft, gotDate bool
|
||||
var date string
|
||||
L:
|
||||
for k, v := range meta {
|
||||
switch k {
|
||||
case "draft":
|
||||
if !v.(bool) {
|
||||
return buff, errors.New("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, errors.New("not a Draft: nothing was done")
|
||||
}
|
||||
|
||||
// get the front matter as bytes and split it into lines
|
||||
var lineEnding []byte
|
||||
fmLines := bytes.Split(fm, []byte("\n"))
|
||||
if len(fmLines) == 1 { // if the result is only 1 element, try to split on dos line endings
|
||||
fmLines = bytes.Split(fm, []byte("\r\n"))
|
||||
if len(fmLines) == 1 {
|
||||
return buff, errors.New("unable to split FrontMatter into lines")
|
||||
}
|
||||
lineEnding = append(lineEnding, []byte("\r\n")...)
|
||||
} else {
|
||||
lineEnding = append(lineEnding, []byte("\n")...)
|
||||
}
|
||||
|
||||
// Write the front matter lines to the buffer, replacing as necessary
|
||||
for _, v := range fmLines {
|
||||
pos := bytes.Index(v, []byte("draft"))
|
||||
if pos != -1 {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
buff.Write(v)
|
||||
buff.Write(lineEnding)
|
||||
}
|
||||
|
||||
// append the actual content
|
||||
buff.Write(p.Content())
|
||||
|
||||
return buff, nil
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2015 The Hugo Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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
|
||||
|
||||
// TODO Support Mac Encoding (\r)
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gohugoio/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---"
|
||||
yamlYesDraftFM = "---\n draft: yes\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, ""},
|
||||
{yamlYesDraftFM, ""},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
r := bytes.NewReader([]byte(test.fm))
|
||||
p, _ := parser.ReadFrom(r)
|
||||
res, err := undraftContent(p)
|
||||
if test.expectedErr != "" {
|
||||
if err == nil {
|
||||
t.Errorf("[%d] Expected error, got none", i)
|
||||
continue
|
||||
}
|
||||
if err.Error() != test.expectedErr {
|
||||
t.Errorf("[%d] Expected %q, got %q", i, test.expectedErr, err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
r = bytes.NewReader(res.Bytes())
|
||||
p, _ = parser.ReadFrom(r)
|
||||
meta, err := p.Metadata()
|
||||
if err != nil {
|
||||
t.Errorf("[%d] unexpected error %q", i, err)
|
||||
continue
|
||||
}
|
||||
for k, v := range meta {
|
||||
if k == "draft" {
|
||||
if v.(bool) {
|
||||
t.Errorf("[%d] Expected %q to be \"false\", got \"true\"", i, k)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if k == "date" {
|
||||
if !strings.HasPrefix(v.(string), time.Now().Format("2006-01-02")) {
|
||||
t.Errorf("[%d] Expected %v to start with %v", i, v.(string), time.Now().Format("2006-01-02"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,7 +75,6 @@ hugo [flags]
|
|||
* [hugo list](/commands/hugo_list/) - Listing out various types of content
|
||||
* [hugo new](/commands/hugo_new/) - Create new content for your site
|
||||
* [hugo server](/commands/hugo_server/) - A high performance webserver
|
||||
* [hugo undraft](/commands/hugo_undraft/) - Undraft resets the content's draft status
|
||||
* [hugo version](/commands/hugo_version/) - Print the version number of Hugo
|
||||
|
||||
###### Auto generated by spf13/cobra on 25-Jan-2018
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
---
|
||||
date: 2018-01-25T10:24:52+01:00
|
||||
title: "hugo undraft"
|
||||
slug: hugo_undraft
|
||||
url: /commands/hugo_undraft/
|
||||
---
|
||||
## hugo undraft
|
||||
|
||||
Undraft resets the content's draft status
|
||||
|
||||
### Synopsis
|
||||
|
||||
Undraft resets the content's draft status
|
||||
and updates the date to the current date and time.
|
||||
If the content's draft status is 'False', nothing is done.
|
||||
|
||||
```
|
||||
hugo undraft path/to/content [flags]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for undraft
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--config string config file (default is path/config.yaml|json|toml)
|
||||
--debug debug output
|
||||
--log enable Logging
|
||||
--logFile string log File path (if set, logging enabled automatically)
|
||||
--quiet build in quiet mode
|
||||
-v, --verbose verbose output
|
||||
--verboseLog verbose logging
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [hugo](/commands/hugo/) - hugo builds your site
|
||||
|
||||
###### Auto generated by spf13/cobra on 25-Jan-2018
|
|
@ -53,7 +53,6 @@ Available Commands:
|
|||
list Listing out various types of content
|
||||
new Create new content for your site
|
||||
server A high performance webserver
|
||||
undraft Undraft resets the content's draft status
|
||||
version Print the version number of Hugo
|
||||
|
||||
Flags:
|
||||
|
|
|
@ -75,13 +75,9 @@ hugo new about.md
|
|||
The preceding example for the about page leverages archetypes to scaffold a new content file with preconfigured front matter. [Find out more about Hugo's archetypes](/content-management/archetypes/).
|
||||
{{% /note %}}
|
||||
|
||||
Now you can edit `contents/about.md` in your text editor of choice, but this is not necessary for the purposes of this guide. Running the following command will build your Hugo site into the `public` directory. We have added `undraft` to ensure that the example page is no longer in draft mode:
|
||||
Now you can edit `contents/about.md` in your text editor of choice, but this is not necessary for the purposes of this guide. Running the following command will build your Hugo site into the `public` directory.
|
||||
|
||||
{{< code file="hugo-build-undraft.sh" >}}
|
||||
hugo undraft content/about.md
|
||||
{{< /code >}}
|
||||
|
||||
Once the website is build, t's a good idea to run the following command to start a local server and ensure you're changes have been implemented:
|
||||
Once the website is build, it's a good idea to run the following command to start a local server and ensure you're changes have been implemented:
|
||||
|
||||
```
|
||||
hugo server --theme=herring-cove
|
||||
|
|
Loading…
Reference in a new issue