mirror of
https://github.com/gohugoio/hugo.git
synced 2024-12-22 14:52:09 +00:00
Adding new commands (new site [path], new theme [name])
This commit is contained in:
parent
be3e5592dc
commit
6b9d4a93da
2 changed files with 221 additions and 16 deletions
178
commands/new.go
178
commands/new.go
|
@ -12,12 +12,16 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/hugo/create"
|
"github.com/spf13/hugo/create"
|
||||||
"github.com/spf13/hugo/helpers"
|
"github.com/spf13/hugo/helpers"
|
||||||
|
"github.com/spf13/hugo/parser"
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
jww "github.com/spf13/jwalterweatherman"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,10 +32,10 @@ var contentFormat string
|
||||||
var contentFrontMatter string
|
var contentFrontMatter string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
//newSiteCmd.Flags().StringVarP(&siteType, "type", "t", "blog", "What type of site to new")
|
newSiteCmd.Flags().StringVarP(&configFormat, "format", "f", "toml", "config & frontmatter format")
|
||||||
newSiteCmd.Flags().StringVarP(&configFormat, "format", "f", "yaml", "Config file format")
|
|
||||||
newCmd.Flags().StringVarP(&contentType, "kind", "k", "", "Content type to create")
|
newCmd.Flags().StringVarP(&contentType, "kind", "k", "", "Content type to create")
|
||||||
newCmd.AddCommand(newSiteCmd)
|
newCmd.AddCommand(newSiteCmd)
|
||||||
|
newCmd.AddCommand(newThemeCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var newCmd = &cobra.Command{
|
var newCmd = &cobra.Command{
|
||||||
|
@ -45,10 +49,32 @@ If archetypes are provided in your theme or site, they will be used.
|
||||||
Run: NewContent,
|
Run: NewContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var newSiteCmd = &cobra.Command{
|
||||||
|
Use: "site [path]",
|
||||||
|
Short: "Create a new site (skeleton)",
|
||||||
|
Long: `Create a new site in the provided directory.
|
||||||
|
The new site will have the correct structure, but no content or theme yet.
|
||||||
|
Use 'hugo new [contentPath]' to create new content.
|
||||||
|
`,
|
||||||
|
Run: NewSite,
|
||||||
|
}
|
||||||
|
|
||||||
|
var newThemeCmd = &cobra.Command{
|
||||||
|
Use: "theme [name]",
|
||||||
|
Short: "Create a new theme",
|
||||||
|
Long: `Create a new theme (skeleton) called [name] in the current directory.
|
||||||
|
New theme is a skeleton. Please add content to the touched files. Add your
|
||||||
|
name to the copyright line in the license and adjust the theme.toml file
|
||||||
|
as you see fit.
|
||||||
|
`,
|
||||||
|
Run: NewTheme,
|
||||||
|
}
|
||||||
|
|
||||||
func NewContent(cmd *cobra.Command, args []string) {
|
func NewContent(cmd *cobra.Command, args []string) {
|
||||||
InitializeConfig()
|
InitializeConfig()
|
||||||
|
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
|
cmd.Usage()
|
||||||
jww.FATAL.Fatalln("path needs to be provided")
|
jww.FATAL.Fatalln("path needs to be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,16 +97,146 @@ func NewContent(cmd *cobra.Command, args []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var newSiteCmd = &cobra.Command{
|
func NewSite(cmd *cobra.Command, args []string) {
|
||||||
Use: "site [type]",
|
if len(args) < 1 {
|
||||||
Short: "Create a new site of [type]",
|
cmd.Usage()
|
||||||
Long: `Create a new site as a (blog, project, etc)`,
|
jww.FATAL.Fatalln("path needs to be provided")
|
||||||
Run: NewSite,
|
}
|
||||||
|
|
||||||
|
createpath, err := filepath.Abs(filepath.Clean(args[0]))
|
||||||
|
if err != nil {
|
||||||
|
cmd.Usage()
|
||||||
|
jww.FATAL.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x, _ := helpers.Exists(createpath); x {
|
||||||
|
jww.FATAL.Fatalln(createpath, "already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir(createpath, "layouts")
|
||||||
|
mkdir(createpath, "content")
|
||||||
|
mkdir(createpath, "archetypes")
|
||||||
|
mkdir(createpath, "static")
|
||||||
|
|
||||||
|
createConfig(createpath, configFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSite(cmd *cobra.Command, args []string) {
|
func NewTheme(cmd *cobra.Command, args []string) {
|
||||||
InitializeConfig()
|
InitializeConfig()
|
||||||
|
|
||||||
fmt.Println("new site called")
|
if len(args) < 1 {
|
||||||
fmt.Println(args)
|
cmd.Usage()
|
||||||
|
jww.FATAL.Fatalln("theme name needs to be provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
createpath := helpers.AbsPathify(path.Join("themes", args[0]))
|
||||||
|
jww.INFO.Println("creating theme at", createpath)
|
||||||
|
|
||||||
|
if x, _ := helpers.Exists(createpath); x {
|
||||||
|
jww.FATAL.Fatalln(createpath, "already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir(createpath, "layouts", "_default")
|
||||||
|
mkdir(createpath, "layouts", "chrome")
|
||||||
|
|
||||||
|
touchFile(createpath, "layouts", "index.html")
|
||||||
|
touchFile(createpath, "layouts", "_default", "list.html")
|
||||||
|
touchFile(createpath, "layouts", "_default", "single.html")
|
||||||
|
|
||||||
|
touchFile(createpath, "layouts", "chrome", "header.html")
|
||||||
|
touchFile(createpath, "layouts", "chrome", "footer.html")
|
||||||
|
|
||||||
|
mkdir(createpath, "archetypes")
|
||||||
|
touchFile(createpath, "archetypes", "default.md")
|
||||||
|
|
||||||
|
mkdir(createpath, "static", "js")
|
||||||
|
mkdir(createpath, "static", "css")
|
||||||
|
|
||||||
|
by := []byte(`The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 YOUR_NAME_HERE
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
`)
|
||||||
|
|
||||||
|
err := helpers.WriteToDisk(path.Join(createpath, "LICENSE.md"), bytes.NewReader(by))
|
||||||
|
if err != nil {
|
||||||
|
jww.FATAL.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
createThemeMD(createpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkdir(x ...string) {
|
||||||
|
p := path.Join(x...)
|
||||||
|
|
||||||
|
err := os.MkdirAll(p, 0777) // rwx, rw, r
|
||||||
|
if err != nil {
|
||||||
|
jww.FATAL.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func touchFile(x ...string) {
|
||||||
|
inpath := path.Join(x...)
|
||||||
|
mkdir(filepath.Dir(inpath))
|
||||||
|
err := helpers.WriteToDisk(inpath, bytes.NewReader([]byte{}))
|
||||||
|
if err != nil {
|
||||||
|
jww.FATAL.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createThemeMD(inpath string) (err error) {
|
||||||
|
|
||||||
|
in := map[string]interface{}{
|
||||||
|
"name": helpers.MakeTitle(filepath.Base(inpath)),
|
||||||
|
"license": "MIT",
|
||||||
|
"source_repo": "",
|
||||||
|
"author": "",
|
||||||
|
"description": "",
|
||||||
|
"tags": []string{"", ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
by, err := parser.InterfaceToConfig(in, parser.FormatToLeadRune("toml"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = helpers.WriteToDisk(path.Join(inpath, "theme.toml"), bytes.NewReader(by))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createConfig(inpath string, kind string) (err error) {
|
||||||
|
in := map[string]string{"baseurl": "http://yourSiteHere", "title": "my new hugo site", "languageCode": "en-us"}
|
||||||
|
kind = parser.FormatSanitize(kind)
|
||||||
|
|
||||||
|
by, err := parser.InterfaceToConfig(in, parser.FormatToLeadRune(kind))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = helpers.WriteToDisk(path.Join(inpath, "config."+kind), bytes.NewReader(by))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,47 @@ type FrontmatterType struct {
|
||||||
includeMark bool
|
includeMark bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InterfaceToConfig(in interface{}, mark rune) ([]byte, error) {
|
||||||
|
if in == nil {
|
||||||
|
return []byte{}, fmt.Errorf("input was nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
|
||||||
|
switch mark {
|
||||||
|
case rune(YAML_LEAD[0]):
|
||||||
|
by, err := goyaml.Marshal(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b.Write(by)
|
||||||
|
_, err = b.Write([]byte("..."))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b.Bytes(), nil
|
||||||
|
case rune(TOML_LEAD[0]):
|
||||||
|
err := toml.NewEncoder(b).Encode(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b.Bytes(), nil
|
||||||
|
case rune(JSON_LEAD[0]):
|
||||||
|
by, err := json.MarshalIndent(in, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b.Write(by)
|
||||||
|
_, err = b.Write([]byte("\n"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b.Bytes(), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unsupported Format provided")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
|
func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return []byte{}, fmt.Errorf("input was nil")
|
return []byte{}, fmt.Errorf("input was nil")
|
||||||
|
@ -60,8 +101,6 @@ func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
|
||||||
|
|
||||||
err = toml.NewEncoder(b).Encode(in)
|
err = toml.NewEncoder(b).Encode(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("toml encoder failed", in)
|
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = b.Write([]byte("\n" + TOML_DELIM_UNIX))
|
_, err = b.Write([]byte("\n" + TOML_DELIM_UNIX))
|
||||||
|
@ -72,8 +111,6 @@ func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
|
||||||
case rune(JSON_LEAD[0]):
|
case rune(JSON_LEAD[0]):
|
||||||
by, err := json.MarshalIndent(in, "", " ")
|
by, err := json.MarshalIndent(in, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("json encoder failed", in)
|
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b.Write(by)
|
b.Write(by)
|
||||||
|
@ -88,7 +125,7 @@ func InterfaceToFrontMatter(in interface{}, mark rune) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatToLeadRune(kind string) rune {
|
func FormatToLeadRune(kind string) rune {
|
||||||
switch strings.ToLower(kind) {
|
switch FormatSanitize(kind) {
|
||||||
case "yaml":
|
case "yaml":
|
||||||
return rune([]byte(YAML_LEAD)[0])
|
return rune([]byte(YAML_LEAD)[0])
|
||||||
case "toml":
|
case "toml":
|
||||||
|
@ -98,7 +135,19 @@ func FormatToLeadRune(kind string) rune {
|
||||||
default:
|
default:
|
||||||
return rune([]byte(TOML_LEAD)[0])
|
return rune([]byte(TOML_LEAD)[0])
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatSanitize(kind string) string {
|
||||||
|
switch strings.ToLower(kind) {
|
||||||
|
case "yaml", "yml":
|
||||||
|
return "yaml"
|
||||||
|
case "toml", "tml":
|
||||||
|
return "toml"
|
||||||
|
case "json", "js":
|
||||||
|
return "json"
|
||||||
|
default:
|
||||||
|
return "toml"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DetectFrontMatter(mark rune) (f *FrontmatterType) {
|
func DetectFrontMatter(mark rune) (f *FrontmatterType) {
|
||||||
|
|
Loading…
Reference in a new issue