github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/create/content.go (about)

     1  // Copyright 2016 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package create provides functions to create new content.
    15  package create
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"os"
    21  	"os/exec"
    22  	"path/filepath"
    23  
    24  	"github.com/gohugoio/hugo/helpers"
    25  	"github.com/gohugoio/hugo/hugolib"
    26  	jww "github.com/spf13/jwalterweatherman"
    27  )
    28  
    29  // NewContent creates a new content file in the content directory based upon the
    30  // given kind, which is used to lookup an archetype.
    31  func NewContent(
    32  	ps *helpers.PathSpec,
    33  	siteFactory func(filename string, siteUsed bool) (*hugolib.Site, error), kind, targetPath string) error {
    34  	ext := helpers.Ext(targetPath)
    35  	fs := ps.BaseFs.SourceFilesystems.Archetypes.Fs
    36  
    37  	jww.INFO.Printf("attempting to create %q of %q of ext %q", targetPath, kind, ext)
    38  
    39  	archetypeFilename := findArchetype(ps, kind, ext)
    40  
    41  	// Building the sites can be expensive, so only do it if really needed.
    42  	siteUsed := false
    43  
    44  	if archetypeFilename != "" {
    45  		f, err := fs.Open(archetypeFilename)
    46  		if err != nil {
    47  			return fmt.Errorf("failed to open archetype file: %s", err)
    48  		}
    49  		defer f.Close()
    50  
    51  		if helpers.ReaderContains(f, []byte(".Site")) {
    52  			siteUsed = true
    53  		}
    54  	}
    55  
    56  	s, err := siteFactory(targetPath, siteUsed)
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	var content []byte
    62  
    63  	content, err = executeArcheTypeAsTemplate(s, kind, targetPath, archetypeFilename)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	// The site may have multiple content dirs, and we currently do not know which contentDir the
    69  	// user wants to create this content in. We should improve on this, but we start by testing if the
    70  	// provided path points to an existing dir. If so, use it as is.
    71  	var contentPath string
    72  	var exists bool
    73  	targetDir := filepath.Dir(targetPath)
    74  
    75  	if targetDir != "" && targetDir != "." {
    76  		exists, _ = helpers.Exists(targetDir, fs)
    77  	}
    78  
    79  	if exists {
    80  		contentPath = targetPath
    81  	} else {
    82  		contentPath = s.PathSpec.AbsPathify(filepath.Join(s.Cfg.GetString("contentDir"), targetPath))
    83  	}
    84  
    85  	if err := helpers.SafeWriteToDisk(contentPath, bytes.NewReader(content), s.Fs.Source); err != nil {
    86  		return err
    87  	}
    88  
    89  	jww.FEEDBACK.Println(contentPath, "created")
    90  
    91  	editor := s.Cfg.GetString("newContentEditor")
    92  	if editor != "" {
    93  		jww.FEEDBACK.Printf("Editing %s with %q ...\n", targetPath, editor)
    94  
    95  		cmd := exec.Command(editor, contentPath)
    96  		cmd.Stdin = os.Stdin
    97  		cmd.Stdout = os.Stdout
    98  		cmd.Stderr = os.Stderr
    99  
   100  		return cmd.Run()
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  // FindArchetype takes a given kind/archetype of content and returns the path
   107  // to the archetype in the archetype filesystem, blank if none found.
   108  func findArchetype(ps *helpers.PathSpec, kind, ext string) (outpath string) {
   109  	fs := ps.BaseFs.Archetypes.Fs
   110  
   111  	// If the new content isn't in a subdirectory, kind == "".
   112  	// Therefore it should be excluded otherwise `is a directory`
   113  	// error will occur. github.com/gohugoio/hugo/issues/411
   114  	var pathsToCheck = []string{"default"}
   115  
   116  	if ext != "" {
   117  		if kind != "" {
   118  			pathsToCheck = append([]string{kind + ext, "default" + ext}, pathsToCheck...)
   119  		} else {
   120  			pathsToCheck = append([]string{"default" + ext}, pathsToCheck...)
   121  		}
   122  	}
   123  
   124  	for _, p := range pathsToCheck {
   125  		if exists, _ := helpers.Exists(p, fs); exists {
   126  			return p
   127  		}
   128  	}
   129  
   130  	return ""
   131  }