summaryrefslogtreecommitdiffstats
path: root/create
diff options
context:
space:
mode:
Diffstat (limited to 'create')
-rw-r--r--create/content.go122
-rw-r--r--create/content_test.go125
2 files changed, 195 insertions, 52 deletions
diff --git a/create/content.go b/create/content.go
index 6d38bbde1..b97744484 100644
--- a/create/content.go
+++ b/create/content.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -15,7 +15,6 @@ package create
import (
"bytes"
- "io/ioutil"
"os"
"os/exec"
"path"
@@ -23,24 +22,26 @@ import (
"strings"
"time"
+ "github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/hugo/helpers"
- "github.com/spf13/hugo/hugofs"
"github.com/spf13/hugo/hugolib"
"github.com/spf13/hugo/parser"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
)
-func NewContent(kind, name string) (err error) {
+// NewContent creates a new content file in the content directory based upon the
+// given kind, which is used to lookup an archetype.
+func NewContent(fs afero.Fs, kind, name string) (err error) {
jww.INFO.Println("attempting to create ", name, "of", kind)
- location := FindArchetype(kind)
+ location := FindArchetype(fs, kind)
var by []byte
if location != "" {
- by, err = ioutil.ReadFile(location)
+ by, err = afero.ReadFile(fs, location)
if err != nil {
jww.ERROR.Println(err)
}
@@ -53,22 +54,64 @@ func NewContent(kind, name string) (err error) {
if err != nil {
return err
}
- metadata, err := psr.Metadata()
+
+ metadata, err := createMetadata(psr, name)
if err != nil {
+ jww.ERROR.Printf("Error processing archetype file %s: %s\n", location, err)
return err
}
- newmetadata, err := cast.ToStringMapE(metadata)
+
+ page, err := hugolib.NewPage(name)
if err != nil {
- jww.ERROR.Println("Error processing archetype file:", location)
return err
}
- for k := range newmetadata {
+ if err = page.SetSourceMetaData(metadata, parser.FormatToLeadRune(viper.GetString("MetaDataFormat"))); err != nil {
+ return
+ }
+
+ page.SetSourceContent(psr.Content())
+
+ if err = page.SafeSaveSourceAs(filepath.Join(viper.GetString("contentDir"), name)); err != nil {
+ return
+ }
+ jww.FEEDBACK.Println(helpers.AbsPathify(filepath.Join(viper.GetString("contentDir"), name)), "created")
+
+ editor := viper.GetString("NewContentEditor")
+
+ if editor != "" {
+ jww.FEEDBACK.Printf("Editing %s with %q ...\n", name, editor)
+
+ cmd := exec.Command(editor, helpers.AbsPathify(path.Join(viper.GetString("contentDir"), name)))
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+
+ return cmd.Run()
+ }
+
+ return nil
+}
+
+// createMetadata generates Metadata for a new page based upon the metadata
+// found in an archetype.
+func createMetadata(archetype parser.Page, name string) (map[string]interface{}, error) {
+ archMetadata, err := archetype.Metadata()
+ if err != nil {
+ return nil, err
+ }
+
+ metadata, err := cast.ToStringMapE(archMetadata)
+ if err != nil {
+ return nil, err
+ }
+
+ for k := range metadata {
switch strings.ToLower(k) {
case "date":
- newmetadata[k] = time.Now()
+ metadata[k] = time.Now()
case "title":
- newmetadata[k] = helpers.MakeTitle(helpers.Filename(name))
+ metadata[k] = helpers.MakeTitle(helpers.Filename(name))
}
}
@@ -81,60 +124,35 @@ func NewContent(kind, name string) (err error) {
return false
}
- if newmetadata == nil {
- newmetadata = make(map[string]interface{})
+ if metadata == nil {
+ metadata = make(map[string]interface{})
}
- if !caseimatch(newmetadata, "date") {
- newmetadata["date"] = time.Now()
+ if !caseimatch(metadata, "date") {
+ metadata["date"] = time.Now()
}
- if !caseimatch(newmetadata, "title") {
- newmetadata["title"] = helpers.MakeTitle(helpers.Filename(name))
- }
-
- page, err := hugolib.NewPage(name)
- if err != nil {
- return err
+ if !caseimatch(metadata, "title") {
+ metadata["title"] = helpers.MakeTitle(helpers.Filename(name))
}
if x := parser.FormatSanitize(viper.GetString("MetaDataFormat")); x == "json" || x == "yaml" || x == "toml" {
- newmetadata["date"] = time.Now().Format(time.RFC3339)
+ metadata["date"] = time.Now().Format(time.RFC3339)
}
- //page.Dir = viper.GetString("sourceDir")
- page.SetSourceMetaData(newmetadata, parser.FormatToLeadRune(viper.GetString("MetaDataFormat")))
- page.SetSourceContent(psr.Content())
- if err = page.SafeSaveSourceAs(filepath.Join(viper.GetString("contentDir"), name)); err != nil {
- return
- }
- jww.FEEDBACK.Println(helpers.AbsPathify(filepath.Join(viper.GetString("contentDir"), name)), "created")
-
- editor := viper.GetString("NewContentEditor")
-
- if editor != "" {
- jww.FEEDBACK.Printf("Editing %s with %q ...\n", name, editor)
-
- cmd := exec.Command(editor, helpers.AbsPathify(path.Join(viper.GetString("contentDir"), name)))
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
-
- if err = cmd.Run(); err != nil {
- return
- }
- }
-
- return nil
+ return metadata, nil
}
-func FindArchetype(kind string) (outpath string) {
+// FindArchetype takes a given kind/archetype of content and returns an output
+// path for that archetype. If no archetype is found, an empty string is
+// returned.
+func FindArchetype(fs afero.Fs, kind string) (outpath string) {
search := []string{helpers.AbsPathify(viper.GetString("archetypeDir"))}
if viper.GetString("theme") != "" {
themeDir := filepath.Join(helpers.AbsPathify(viper.GetString("themesDir")+"/"+viper.GetString("theme")), "/archetypes/")
- if _, err := os.Stat(themeDir); os.IsNotExist(err) {
- jww.ERROR.Println("Unable to find archetypes directory for theme :", viper.GetString("theme"), "in", themeDir)
+ if _, err := fs.Stat(themeDir); os.IsNotExist(err) {
+ jww.ERROR.Printf("Unable to find archetypes directory for theme %q at %q", viper.GetString("theme"), themeDir)
} else {
search = append(search, themeDir)
}
@@ -154,7 +172,7 @@ func FindArchetype(kind string) (outpath string) {
for _, p := range pathsToCheck {
curpath := filepath.Join(x, p)
jww.DEBUG.Println("checking", curpath, "for archetypes")
- if exists, _ := helpers.Exists(curpath, hugofs.SourceFs); exists {
+ if exists, _ := helpers.Exists(curpath, fs); exists {
jww.INFO.Println("curpath: " + curpath)
return curpath
}
diff --git a/create/content_test.go b/create/content_test.go
new file mode 100644
index 000000000..f0b3de1a0
--- /dev/null
+++ b/create/content_test.go
@@ -0,0 +1,125 @@
+// Copyright 2016 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 create_test
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/spf13/afero"
+ "github.com/spf13/hugo/create"
+ "github.com/spf13/hugo/hugofs"
+ "github.com/spf13/viper"
+)
+
+func TestNewContent(t *testing.T) {
+ initViper()
+
+ err := initFs()
+ if err != nil {
+ t.Fatalf("initialization error: %s", err)
+ }
+
+ cases := []struct {
+ kind string
+ path string
+ resultStrings []string
+ }{
+ {"post", "post/sample-1.md", []string{`title = "sample 1"`, `test = "test1"`}},
+ {"stump", "stump/sample-2.md", []string{`title = "sample 2"`}}, // no archetype file
+ {"", "sample-3.md", []string{`title = "sample 3"`}}, // no archetype
+ {"product", "product/sample-4.md", []string{`title = "sample 4"`}}, // empty archetype front matter
+ }
+
+ for i, c := range cases {
+ err = create.NewContent(hugofs.SourceFs, c.kind, c.path)
+ if err != nil {
+ t.Errorf("[%d] NewContent: %s", i, err)
+ }
+
+ fname := filepath.Join(os.TempDir(), "content", filepath.FromSlash(c.path))
+ _, err = hugofs.SourceFs.Stat(fname)
+ if err != nil {
+ t.Errorf("[%d] Stat: %s", i, err)
+ }
+
+ for _, v := range c.resultStrings {
+ found, err := afero.FileContainsBytes(hugofs.SourceFs, fname, []byte(v))
+ if err != nil {
+ t.Errorf("[%d] FileContainsBytes: %s", i, err)
+ }
+ if !found {
+ t.Errorf("content missing from output: %q", v)
+ }
+ }
+ }
+}
+
+func initViper() {
+ viper.Reset()
+ viper.Set("MetaDataFormat", "toml")
+ viper.Set("archetypeDir", filepath.Join(os.TempDir(), "archetypes"))
+ viper.Set("contentDir", filepath.Join(os.TempDir(), "content"))
+ viper.Set("themesDir", filepath.Join(os.TempDir(), "themes"))
+ viper.Set("theme", "sample")
+}
+
+func initFs() error {
+ hugofs.SourceFs = new(afero.MemMapFs)
+ perm := os.FileMode(0755)
+ var err error
+
+ // create directories
+ dirs := []string{
+ "archetypes",
+ "content",
+ filepath.Join("themes", "sample", "archetypes"),
+ }
+ for _, dir := range dirs {
+ dir = filepath.Join(os.TempDir(), dir)
+ err = hugofs.SourceFs.Mkdir(dir, perm)
+ if err != nil {
+ return err
+ }
+ }
+
+ // create files
+ for _, v := range []struct {
+ path string
+ content string
+ }{
+ {
+ path: filepath.Join(os.TempDir(), "archetypes", "post.md"),
+ content: "+++\ndate = \"2015-01-12T19:20:04-07:00\"\ntitle = \"post arch\"\ntest = \"test1\"\n+++\n",
+ },
+ {
+ path: filepath.Join(os.TempDir(), "archetypes", "product.md"),
+ content: "+++\n+++\n",
+ },
+ } {
+ f, err := hugofs.SourceFs.Create(v.path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ _, err = f.Write([]byte(v.content))
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}