Preliminary Theme Support

This commit is contained in:
spf13 2014-04-10 08:10:12 -04:00
parent c0a046cbfb
commit 8afff8c7c4
3 changed files with 120 additions and 38 deletions

View file

@ -49,7 +49,7 @@ Complete documentation is available at http://hugo.spf13.com`,
var hugoCmdV *cobra.Command var hugoCmdV *cobra.Command
var BuildWatch, Draft, UglyUrls, Verbose, Logging, VerboseLog, DisableRSS bool var BuildWatch, Draft, UglyUrls, Verbose, Logging, VerboseLog, DisableRSS bool
var Source, Destination, BaseUrl, CfgFile, LogFile string var Source, Destination, Theme, BaseUrl, CfgFile, LogFile string
func Execute() { func Execute() {
AddCommands() AddCommands()
@ -68,6 +68,7 @@ func init() {
HugoCmd.PersistentFlags().BoolVar(&DisableRSS, "disableRSS", false, "Do not build RSS files") HugoCmd.PersistentFlags().BoolVar(&DisableRSS, "disableRSS", false, "Do not build RSS files")
HugoCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from") HugoCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
HugoCmd.PersistentFlags().StringVarP(&Destination, "destination", "d", "", "filesystem path to write files to") HugoCmd.PersistentFlags().StringVarP(&Destination, "destination", "d", "", "filesystem path to write files to")
HugoCmd.PersistentFlags().StringVarP(&Theme, "theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
HugoCmd.PersistentFlags().BoolVar(&UglyUrls, "uglyurls", false, "if true, use /filename.html instead of /filename/") HugoCmd.PersistentFlags().BoolVar(&UglyUrls, "uglyurls", false, "if true, use /filename.html instead of /filename/")
HugoCmd.PersistentFlags().StringVarP(&BaseUrl, "base-url", "b", "", "hostname (and path) to the root eg. http://spf13.com/") HugoCmd.PersistentFlags().StringVarP(&BaseUrl, "base-url", "b", "", "hostname (and path) to the root eg. http://spf13.com/")
@ -126,6 +127,11 @@ func InitializeConfig() {
} }
viper.Set("BaseUrl", BaseUrl) viper.Set("BaseUrl", BaseUrl)
} }
if Theme != "" {
viper.Set("theme", Theme)
}
if Destination != "" { if Destination != "" {
viper.Set("PublishDir", Destination) viper.Set("PublishDir", Destination)
} }
@ -176,10 +182,24 @@ func build(watches ...bool) {
func copyStatic() error { func copyStatic() error {
staticDir := helpers.AbsPathify(viper.GetString("StaticDir")) + "/" staticDir := helpers.AbsPathify(viper.GetString("StaticDir")) + "/"
if _, err := os.Stat(staticDir); os.IsNotExist(err) { if _, err := os.Stat(staticDir); os.IsNotExist(err) {
jww.ERROR.Println("Unable to find Static Directory:", viper.GetString("theme"), "in", staticDir)
return nil return nil
} }
publishDir := helpers.AbsPathify(viper.GetString("PublishDir")) + "/" publishDir := helpers.AbsPathify(viper.GetString("PublishDir")) + "/"
if themeSet() {
themeDir := helpers.AbsPathify("themes/"+viper.GetString("theme")) + "/static/"
if _, err := os.Stat(themeDir); os.IsNotExist(err) {
jww.ERROR.Println("Unable to find static directory for theme :", viper.GetString("theme"), "in", themeDir)
return nil
}
// Copy Static to Destination
jww.INFO.Println("syncing from", themeDir, "to", publishDir)
return fsync.Sync(publishDir, themeDir)
}
// Copy Static to Destination // Copy Static to Destination
jww.INFO.Println("syncing from", staticDir, "to", publishDir) jww.INFO.Println("syncing from", staticDir, "to", publishDir)
return fsync.Sync(publishDir, staticDir) return fsync.Sync(publishDir, staticDir)
@ -202,10 +222,17 @@ func getDirList() []string {
filepath.Walk(helpers.AbsPathify(viper.GetString("ContentDir")), walker) filepath.Walk(helpers.AbsPathify(viper.GetString("ContentDir")), walker)
filepath.Walk(helpers.AbsPathify(viper.GetString("LayoutDir")), walker) filepath.Walk(helpers.AbsPathify(viper.GetString("LayoutDir")), walker)
filepath.Walk(helpers.AbsPathify(viper.GetString("StaticDir")), walker) filepath.Walk(helpers.AbsPathify(viper.GetString("StaticDir")), walker)
if themeSet() {
filepath.Walk(helpers.AbsPathify("themes/"+viper.GetString("theme")), walker)
}
return a return a
} }
func themeSet() bool {
return viper.GetString("theme") != ""
}
func buildSite(watching ...bool) (err error) { func buildSite(watching ...bool) (err error) {
startTime := time.Now() startTime := time.Now()
site := &hugolib.Site{} site := &hugolib.Site{}

View file

@ -1,4 +1,4 @@
// Copyright © 2013 Steve Francia <spf@spf13.com>. // Copyright © 2013-14 Steve Francia <spf@spf13.com>.
// //
// Licensed under the Simple Public License, Version 2.0 (the "License"); // Licensed under the Simple Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -132,6 +132,9 @@ func (s *Site) Analyze() {
func (s *Site) prepTemplates() { func (s *Site) prepTemplates() {
s.Tmpl = bundle.NewTemplate() s.Tmpl = bundle.NewTemplate()
s.Tmpl.LoadTemplates(s.absLayoutDir()) s.Tmpl.LoadTemplates(s.absLayoutDir())
if s.hasTheme() {
s.Tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
}
} }
func (s *Site) addTemplate(name, data string) error { func (s *Site) addTemplate(name, data string) error {
@ -244,6 +247,14 @@ func (s *Site) initializeSiteInfo() {
} }
} }
func (s *Site) hasTheme() bool {
return viper.GetString("theme") != ""
}
func (s *Site) absThemeDir() string {
return helpers.AbsPathify("themes/" + viper.GetString("theme"))
}
func (s *Site) absLayoutDir() string { func (s *Site) absLayoutDir() string {
return helpers.AbsPathify(viper.GetString("LayoutDir")) return helpers.AbsPathify(viper.GetString("LayoutDir"))
} }
@ -422,7 +433,7 @@ func (s *Site) RenderPages() (err error) {
layouts = append(layouts, "_default/single.html") layouts = append(layouts, "_default/single.html")
} }
return s.render(p, p.TargetPath(), layouts...) return s.render(p, p.TargetPath(), s.appendThemeTemplates(layouts)...)
}(page) }(page)
} }
wg.Wait() wg.Wait()
@ -433,6 +444,34 @@ func (s *Site) RenderPages() (err error) {
return nil return nil
} }
func (s *Site) appendThemeTemplates(in []string) []string {
if s.hasTheme() {
out := []string{}
// First place all non internal templates
for _, t := range in {
if !strings.HasPrefix("_internal/", t) {
out = append(out, t)
}
}
// Then place theme templates with the same names
for _, t := range in {
if !strings.HasPrefix("_internal/", t) {
out = append(out, "theme/"+t)
}
}
// Lastly place internal templates
for _, t := range in {
if strings.HasPrefix("_internal/", t) {
out = append(out, "theme/"+t)
}
}
return out
} else {
return in
}
}
// Render the listing pages based on the meta data // Render the listing pages based on the meta data
// each unique term within a taxonomy will have a page created // each unique term within a taxonomy will have a page created
func (s *Site) RenderTaxonomiesLists() (err error) { func (s *Site) RenderTaxonomiesLists() (err error) {
@ -451,8 +490,8 @@ func (s *Site) RenderTaxonomiesLists() (err error) {
n.Date = o[0].Page.Date n.Date = o[0].Page.Date
n.Data[singular] = o n.Data[singular] = o
n.Data["Pages"] = o.Pages() n.Data["Pages"] = o.Pages()
err = s.render(n, base+".html", "taxonomies/"+singular+".html", "indexes/"+singular+".html") layouts := []string{"taxonomy/" + singular + ".html", "indexes/" + singular + ".html", "_default/taxonomy.html", "_default/list.html"}
//TODO add , "_default/taxonomy.html", "_default/list.html" err = s.render(n, base+".html", s.appendThemeTemplates(layouts)...)
if err != nil { if err != nil {
return err return err
} }
@ -460,7 +499,8 @@ func (s *Site) RenderTaxonomiesLists() (err error) {
if !viper.GetBool("DisableRSS") { if !viper.GetBool("DisableRSS") {
// XML Feed // XML Feed
s.setUrls(n, base+".xml") s.setUrls(n, base+".xml")
err := s.render(n, base+".xml", "rss.xml", "_internal/_default/rss.xml") rssLayouts := []string{"taxonomy/" + singular + ".rss.xml", "_default/rss.xml", "rss.xml", "_internal/_default/rss.xml"}
err := s.render(n, base+".xml", s.appendThemeTemplates(rssLayouts)...)
if err != nil { if err != nil {
return err return err
} }
@ -475,28 +515,27 @@ func (s *Site) RenderTaxonomiesLists() (err error) {
// Render a page per taxonomy that lists the terms for that taxonomy // Render a page per taxonomy that lists the terms for that taxonomy
func (s *Site) RenderListsOfTaxonomyTerms() (err error) { func (s *Site) RenderListsOfTaxonomyTerms() (err error) {
layouts := []string{"taxonomies/termslist.html", "indexes/indexes.html"} taxonomies := viper.GetStringMapString("Taxonomies")
// TODO add "_default/termsList.html", "_default/termslist.html" for singular, plural := range taxonomies {
// TODO add support for unique taxonomy terms list (`single`terms.html) n := s.NewNode()
if s.layoutExists(layouts...) { n.Title = strings.Title(plural)
taxonomies := viper.GetStringMapString("Taxonomies") s.setUrls(n, plural)
for singular, plural := range taxonomies { n.Data["Singular"] = singular
n := s.NewNode() n.Data["Plural"] = plural
n.Title = strings.Title(plural) n.Data["Terms"] = s.Taxonomies[plural]
s.setUrls(n, plural) // keep the following just for legacy reasons
n.Data["Singular"] = singular n.Data["OrderedIndex"] = n.Data["Terms"]
n.Data["Plural"] = plural n.Data["Index"] = n.Data["Terms"]
n.Data["Terms"] = s.Taxonomies[plural] layouts := []string{"taxonomy/" + singular + ".terms.html", "_default/terms.html", "indexes/indexes.html"}
// keep the following just for legacy reasons layouts = s.appendThemeTemplates(layouts)
n.Data["OrderedIndex"] = n.Data["Terms"] if s.layoutExists(layouts...) {
n.Data["Index"] = n.Data["Terms"]
err := s.render(n, plural+"/index.html", layouts...) err := s.render(n, plural+"/index.html", layouts...)
if err != nil { if err != nil {
return err return err
} }
} }
} }
return return
} }
@ -508,17 +547,18 @@ func (s *Site) RenderSectionLists() error {
s.setUrls(n, section) s.setUrls(n, section)
n.Date = data[0].Page.Date n.Date = data[0].Page.Date
n.Data["Pages"] = data.Pages() n.Data["Pages"] = data.Pages()
layouts := []string{"section/" + section + ".html", "_default/section.html", "_default/list.html", "indexes/" + section + ".html", "_default/indexes.html"}
err := s.render(n, section, "section/"+section+".html", "indexes/"+section+".html", "_default/section.html", "_default/list.html", "_default/indexes.html") err := s.render(n, section, s.appendThemeTemplates(layouts)...)
if err != nil { if err != nil {
return err return err
} }
if !viper.GetBool("DisableRSS") { if !viper.GetBool("DisableRSS") {
// XML Feed // XML Feed
rssLayouts := []string{"section/" + section + ".rss.xml", "_default/rss.xml", "rss.xml", "_internal/_default/rss.xml"}
s.setUrls(n, section+".xml") s.setUrls(n, section+".xml")
err = s.render(n, section+".xml", "rss.xml", "_internal/_default/rss.xml") err = s.render(n, section+".xml", s.appendThemeTemplates(rssLayouts)...)
//TODO add section specific rss
if err != nil { if err != nil {
return err return err
} }
@ -532,7 +572,8 @@ func (s *Site) RenderHomePage() error {
n.Title = n.Site.Title n.Title = n.Site.Title
s.setUrls(n, "/") s.setUrls(n, "/")
n.Data["Pages"] = s.Pages n.Data["Pages"] = s.Pages
err := s.render(n, "/", "index.html") layouts := []string{"index.html"}
err := s.render(n, "/", s.appendThemeTemplates(layouts)...)
if err != nil { if err != nil {
return err return err
} }
@ -550,9 +591,13 @@ func (s *Site) RenderHomePage() error {
if len(s.Pages) > 0 { if len(s.Pages) > 0 {
n.Date = s.Pages[0].Date n.Date = s.Pages[0].Date
} }
err := s.render(n, ".xml", "rss.xml", "_internal/_default/rss.xml")
if err != nil { if !viper.GetBool("DisableRSS") {
return err rssLayouts := []string{"rss.xml", "_default/rss.xml", "_internal/_default/rss.xml"}
err := s.render(n, ".xml", s.appendThemeTemplates(rssLayouts)...)
if err != nil {
return err
}
} }
} }
@ -560,7 +605,9 @@ func (s *Site) RenderHomePage() error {
n.Url = helpers.Urlize("404.html") n.Url = helpers.Urlize("404.html")
n.Title = "404 Page not found" n.Title = "404 Page not found"
n.Permalink = s.permalink("404.html") n.Permalink = s.permalink("404.html")
return s.render(n, "404.html", "404.html")
layouts := []string{"404.html"}
return s.render(n, "404.html", s.appendThemeTemplates(layouts)...)
} }
return nil return nil

View file

@ -138,6 +138,7 @@ type Template interface {
Templates() []*template.Template Templates() []*template.Template
New(name string) *template.Template New(name string) *template.Template
LoadTemplates(absPath string) LoadTemplates(absPath string)
LoadTemplatesWithPrefix(absPath, prefix string)
AddTemplate(name, tpl string) error AddTemplate(name, tpl string) error
AddInternalTemplate(prefix, name, tpl string) error AddInternalTemplate(prefix, name, tpl string) error
AddInternalShortcode(name, tpl string) error AddInternalShortcode(name, tpl string) error
@ -211,12 +212,7 @@ func (t *GoHtmlTemplate) AddTemplateFile(name, path string) error {
if err != nil { if err != nil {
return err return err
} }
s := string(b) return t.AddTemplate(name, string(b))
_, err = t.New(name).Parse(s)
if err != nil {
t.errors = append(t.errors, &templateErr{name: name, err: err})
}
return err
} }
func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string { func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string {
@ -227,7 +223,7 @@ func ignoreDotFile(path string) bool {
return filepath.Base(path)[0] == '.' return filepath.Base(path)[0] == '.'
} }
func (t *GoHtmlTemplate) LoadTemplates(absPath string) { func (t *GoHtmlTemplate) loadTemplates(absPath string, prefix string) {
walker := func(path string, fi os.FileInfo, err error) error { walker := func(path string, fi os.FileInfo, err error) error {
if err != nil { if err != nil {
return nil return nil
@ -240,6 +236,11 @@ func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
tplName := t.generateTemplateNameFrom(absPath, path) tplName := t.generateTemplateNameFrom(absPath, path)
if prefix != "" {
tplName = strings.Trim(prefix, "/") + "/" + tplName
}
// TODO move this into the AddTemplateFile function
if strings.HasSuffix(path, ".amber") { if strings.HasSuffix(path, ".amber") {
compiler := amber.New() compiler := amber.New()
// Parse the input file // Parse the input file
@ -247,7 +248,6 @@ func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
return nil return nil
} }
// note t.New(tplName)
if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil { if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil {
return err return err
} }
@ -261,3 +261,11 @@ func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
filepath.Walk(absPath, walker) filepath.Walk(absPath, walker)
} }
func (t *GoHtmlTemplate) LoadTemplatesWithPrefix(absPath string, prefix string) {
t.loadTemplates(absPath, prefix)
}
func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
t.loadTemplates(absPath, "")
}