Adding new commands (new site [path], new theme [name])

This commit is contained in:
spf13 2014-05-08 18:30:11 -04:00
parent be3e5592dc
commit 6b9d4a93da
2 changed files with 221 additions and 16 deletions

View file

@ -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
} }

View file

@ -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) {