diff --git a/hugolib/helpers.go b/hugolib/helpers.go deleted file mode 100644 index f9283f4b8..000000000 --- a/hugolib/helpers.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright © 2013 Steve Francia . -// -// 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 obtain a copy of the License at -// http://opensource.org/licenses/Simple-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 hugolib - -import ( - "bytes" - "html/template" - "errors" - "fmt" - "github.com/kr/pretty" - "os" - "os/exec" - "reflect" - "regexp" - "strconv" - "strings" - "time" -) - -var sanitizeRegexp = regexp.MustCompile("[^a-zA-Z0-9./_-]") -var summaryLength = 70 -var summaryDivider = []byte("") - -// TODO: Make these wrappers private -// Wrapper around Fprintf taking verbose flag in account. -func Printvf(format string, a ...interface{}) { - //if *verbose { - fmt.Fprintf(os.Stderr, format, a...) - //} -} - -func Printer(x interface{}) { - fmt.Printf("%#v", pretty.Formatter(x)) - fmt.Println("") -} - -// Wrapper around Fprintln taking verbose flag in account. -func Printvln(a ...interface{}) { - //if *verbose { - fmt.Fprintln(os.Stderr, a...) - //} -} - -func FatalErr(str string) { - fmt.Println(str) - os.Exit(1) -} - -func PrintErr(str string, a ...interface{}) { - fmt.Fprintln(os.Stderr, str, a) -} - -func Error(str string, a ...interface{}) { - fmt.Fprintln(os.Stderr, str, a) -} - -func interfaceToStringToDate(i interface{}) time.Time { - s := interfaceToString(i) - - if d, e := parseDateWith(s, []string{ - time.RFC3339, - time.RFC1123Z, - time.RFC1123, - time.RFC822Z, - time.RFC822, - time.ANSIC, - time.UnixDate, - time.RubyDate, - "2006-01-02 15:04:05Z07:00", - "02 Jan 06 15:04 MST", - "2006-01-02", - "02 Jan 2006", - }); e == nil { - return d - } - - return time.Unix(0, 0) -} - -func parseDateWith(s string, dates []string) (d time.Time, e error) { - for _, dateType := range dates { - if d, e = time.Parse(dateType, s); e == nil { - return - } - } - return d, errors.New(fmt.Sprintf("Unable to parse date: %s", s)) -} - -func interfaceToBool(i interface{}) bool { - switch b := i.(type) { - case bool: - return b - default: - Error("Only Boolean values are supported for this YAML key") - } - - return false - -} - -func interfaceArrayToStringArray(i interface{}) []string { - var a []string - - switch vv := i.(type) { - case []interface{}: - for _, u := range vv { - a = append(a, interfaceToString(u)) - } - } - - return a -} - -func interfaceToString(i interface{}) string { - switch s := i.(type) { - case string: - return s - default: - Error("Only Strings are supported for this YAML key") - } - - return "" -} - -// Check if Exists && is Directory -func dirExists(path string) (bool, error) { - fi, err := os.Stat(path) - if err == nil && fi.IsDir() { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -// Check if File / Directory Exists -func exists(path string) (bool, error) { - _, err := os.Stat(path) - if err == nil { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -func mkdirIf(path string) error { - return os.MkdirAll(path, 0777) -} - -func Urlize(url string) string { - return Sanitize(strings.ToLower(strings.Replace(strings.TrimSpace(url), " ", "-", -1))) -} - -func AbsUrl(url string, base string) template.HTML { - if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") { - return template.HTML(url) - } - return template.HTML(MakePermalink(base, url)) -} - -func Gt(a interface{}, b interface{}) bool { - var left, right int64 - av := reflect.ValueOf(a) - - switch av.Kind() { - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: - left = int64(av.Len()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - left = av.Int() - case reflect.String: - left, _ = strconv.ParseInt(av.String(), 10, 64) - } - - bv := reflect.ValueOf(b) - - switch bv.Kind() { - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: - right = int64(bv.Len()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - right = bv.Int() - case reflect.String: - right, _ = strconv.ParseInt(bv.String(), 10, 64) - } - - return left > right -} - -func IsSet(a interface{}, key interface{}) bool { - av := reflect.ValueOf(a) - kv := reflect.ValueOf(key) - - switch av.Kind() { - case reflect.Array, reflect.Chan, reflect.Slice: - if int64(av.Len()) > kv.Int() { - return true - } - case reflect.Map: - if kv.Type() == av.Type().Key() { - return av.MapIndex(kv).IsValid() - } - } - - return false -} - -func ReturnWhenSet(a interface{}, index int) interface{} { - av := reflect.ValueOf(a) - - switch av.Kind() { - case reflect.Array, reflect.Slice: - if av.Len() > index { - - avv := av.Index(index) - switch avv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return avv.Int() - case reflect.String: - return avv.String() - } - } - } - - return "" -} - -func Sanitize(s string) string { - return sanitizeRegexp.ReplaceAllString(s, "") -} - -func fileExt(path string) (file, ext string) { - if strings.Contains(path, ".") { - i := len(path) - 1 - for path[i] != '.' { - i-- - } - return path[:i], path[i+1:] - } - return path, "" -} - -func replaceExtension(path string, newExt string) string { - f, _ := fileExt(path) - return f + "." + newExt -} - -func TotalWords(s string) int { - return len(strings.Fields(s)) -} - -func WordCount(s string) map[string]int { - m := make(map[string]int) - for _, f := range strings.Fields(s) { - m[f] += 1 - } - - return m -} - -func RemoveSummaryDivider(content []byte) []byte { - return bytes.Replace(content, summaryDivider, []byte(""), -1) -} - -func StripHTML(s string) string { - output := "" - - // Shortcut strings with no tags in them - if !strings.ContainsAny(s, "<>") { - output = s - } else { - s = strings.Replace(s, "\n", " ", -1) - s = strings.Replace(s, "

", " \n", -1) - s = strings.Replace(s, "
", " \n", -1) - s = strings.Replace(s, "
", " \n", -1) - - // Walk through the string removing all tags - b := new(bytes.Buffer) - inTag := false - for _, r := range s { - switch r { - case '<': - inTag = true - case '>': - inTag = false - default: - if !inTag { - b.WriteRune(r) - } - } - } - output = b.String() - } - return output -} - -func TruncateWords(s string, max int) string { - words := strings.Fields(s) - if max > len(words) { - return strings.Join(words, " ") - } - - return strings.Join(words[:max], " ") -} - -func TruncateWordsToWholeSentence(s string, max int) string { - words := strings.Fields(s) - if max > len(words) { - return strings.Join(words, " ") - } - - for counter, word := range words[max:] { - if strings.HasSuffix(word, ".") || - strings.HasSuffix(word, "?") || - strings.HasSuffix(word, ".\"") || - strings.HasSuffix(word, "!") { - return strings.Join(words[:max+counter+1], " ") - } - } - - return strings.Join(words[:max], " ") -} - -func MakePermalink(domain string, path string) string { - return strings.TrimRight(domain, "/") + "/" + strings.TrimLeft(path, "/") -} - -func getSummaryString(content []byte) ([]byte, bool) { - if bytes.Contains(content, summaryDivider) { - return bytes.Split(content, summaryDivider)[0], false - } else { - plainContent := StripHTML(StripShortcodes(string(content))) - return []byte(TruncateWordsToWholeSentence(plainContent, summaryLength)), true - } -} - -func getRstContent(content []byte) string { - cleanContent := bytes.Replace(content, summaryDivider, []byte(""), 1) - - cmd := exec.Command("rst2html.py", "--leave-comments") - cmd.Stdin = bytes.NewReader(cleanContent) - var out bytes.Buffer - cmd.Stdout = &out - if err := cmd.Run(); err != nil { - fmt.Println(err) - } - - rstLines := strings.Split(out.String(), "\n") - for i, line := range rstLines { - if strings.HasPrefix(line, "") { - rstLines = (rstLines[i+1 : len(rstLines)-3]) - } - } - return strings.Join(rstLines, "\n") -} diff --git a/hugolib/index.go b/hugolib/index.go index 92232b319..f52c372b6 100644 --- a/hugolib/index.go +++ b/hugolib/index.go @@ -14,6 +14,7 @@ package hugolib import ( + "github.com/spf13/hugo/template" "sort" ) @@ -30,7 +31,7 @@ type OrderedIndexList map[string]OrderedIndex // KeyPrep... Indexes should be case insensitive. Can make it easily conditional later. func kp(in string) string { - return Urlize(in) + return template.Urlize(in) } func (i Index) Get(key string) Pages { return i[kp(key)] } diff --git a/hugolib/metadata.go b/hugolib/metadata.go new file mode 100644 index 000000000..3bb353a15 --- /dev/null +++ b/hugolib/metadata.go @@ -0,0 +1,81 @@ +package hugolib + +import ( + "errors" + "fmt" + "os" + "time" +) + +func interfaceToStringToDate(i interface{}) time.Time { + s := interfaceToString(i) + + if d, e := parseDateWith(s, []string{ + time.RFC3339, + time.RFC1123Z, + time.RFC1123, + time.RFC822Z, + time.RFC822, + time.ANSIC, + time.UnixDate, + time.RubyDate, + "2006-01-02 15:04:05Z07:00", + "02 Jan 06 15:04 MST", + "2006-01-02", + "02 Jan 2006", + }); e == nil { + return d + } + + return time.Unix(0, 0) +} + +// TODO remove this and return a proper error. +func errorf(str string, a ...interface{}) { + fmt.Fprintln(os.Stderr, str, a) +} + +func parseDateWith(s string, dates []string) (d time.Time, e error) { + for _, dateType := range dates { + if d, e = time.Parse(dateType, s); e == nil { + return + } + } + return d, errors.New(fmt.Sprintf("Unable to parse date: %s", s)) +} + +func interfaceToBool(i interface{}) bool { + switch b := i.(type) { + case bool: + return b + default: + errorf("Only Boolean values are supported for this YAML key") + } + + return false + +} + +func interfaceArrayToStringArray(i interface{}) []string { + var a []string + + switch vv := i.(type) { + case []interface{}: + for _, u := range vv { + a = append(a, interfaceToString(u)) + } + } + + return a +} + +func interfaceToString(i interface{}) string { + switch s := i.(type) { + case string: + return s + default: + errorf("Only Strings are supported for this YAML key") + } + + return "" +} diff --git a/hugolib/node.go b/hugolib/node.go index 404944d9d..918edeb5e 100644 --- a/hugolib/node.go +++ b/hugolib/node.go @@ -14,8 +14,8 @@ package hugolib import ( - "time" "html/template" + "time" ) type Node struct { diff --git a/hugolib/page.go b/hugolib/page.go index a8629250b..5152578d0 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -20,9 +20,11 @@ import ( "errors" "fmt" "github.com/BurntSushi/toml" + helper "github.com/spf13/hugo/template" + "github.com/spf13/hugo/template/bundle" "github.com/theplant/blackfriday" - "io" "html/template" + "io" "io/ioutil" "launchpad.net/goyaml" "os" @@ -46,7 +48,7 @@ type Page struct { contentType string Draft bool Aliases []string - Tmpl Template + Tmpl bundle.Template Markup string PageMeta File @@ -78,6 +80,15 @@ func (p Pages) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p Pages) Sort() { sort.Sort(p) } func (p Pages) Limit(n int) Pages { return p[0:n] } +func getSummaryString(content []byte) ([]byte, bool) { + if bytes.Contains(content, summaryDivider) { + return bytes.Split(content, summaryDivider)[0], false + } else { + plainContent := StripHTML(StripShortcodes(string(content))) + return []byte(TruncateWordsToWholeSentence(plainContent, summaryLength)), true + } +} + // TODO abstract further to support loading from more // than just files on disk. Should load reader (file, []byte) func NewPage(filename string) *Page { @@ -91,6 +102,38 @@ func NewPage(filename string) *Page { return &page } +func StripHTML(s string) string { + output := "" + + // Shortcut strings with no tags in them + if !strings.ContainsAny(s, "<>") { + output = s + } else { + s = strings.Replace(s, "\n", " ", -1) + s = strings.Replace(s, "

", " \n", -1) + s = strings.Replace(s, "
", " \n", -1) + s = strings.Replace(s, "
", " \n", -1) + + // Walk through the string removing all tags + b := new(bytes.Buffer) + inTag := false + for _, r := range s { + switch r { + case '<': + inTag = true + case '>': + inTag = false + default: + if !inTag { + b.WriteRune(r) + } + } + } + output = b.String() + } + return output +} + func (page *Page) Initalize() error { err := page.buildPageFromFile() if err != nil { @@ -246,12 +289,12 @@ func (page *Page) update(f interface{}) error { case "description": page.Description = interfaceToString(v) case "slug": - page.Slug = Urlize(interfaceToString(v)) + page.Slug = helper.Urlize(interfaceToString(v)) case "url": if url := interfaceToString(v); strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") { return fmt.Errorf("Only relative urls are supported, %v provided", url) } - page.Url = Urlize(interfaceToString(v)) + page.Url = helper.Urlize(interfaceToString(v)) case "type": page.contentType = interfaceToString(v) case "keywords": diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 7780a1cff..4c8968ba9 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -1,11 +1,11 @@ package hugolib import ( + "html/template" "path/filepath" - "time" "strings" "testing" - "html/template" + "time" ) var EMPTY_PAGE = "" diff --git a/hugolib/path.go b/hugolib/path.go new file mode 100644 index 000000000..03a5dba04 --- /dev/null +++ b/hugolib/path.go @@ -0,0 +1,34 @@ +package hugolib + +import ( + "os" + "strings" +) + +func fileExt(path string) (file, ext string) { + if strings.Contains(path, ".") { + i := len(path) - 1 + for path[i] != '.' { + i-- + } + return path[:i], path[i+1:] + } + return path, "" +} + +func replaceExtension(path string, newExt string) string { + f, _ := fileExt(path) + return f + "." + newExt +} + +// Check if Exists && is Directory +func dirExists(path string) (bool, error) { + fi, err := os.Stat(path) + if err == nil && fi.IsDir() { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go index eede060cd..4d68b2fe8 100644 --- a/hugolib/shortcode.go +++ b/hugolib/shortcode.go @@ -16,6 +16,7 @@ package hugolib import ( "bytes" "fmt" + "github.com/spf13/hugo/template/bundle" "strings" "unicode" ) @@ -36,7 +37,7 @@ type ShortcodeWithPage struct { type Shortcodes map[string]ShortcodeFunc -func ShortcodesHandle(stringToParse string, p *Page, t Template) string { +func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string { posStart := strings.Index(stringToParse, "{{%") if posStart > 0 { posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart @@ -123,7 +124,7 @@ func SplitParams(in string) (name string, par2 string) { return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:]) } -func ShortcodeRender(name string, data *ShortcodeWithPage, t Template) string { +func ShortcodeRender(name string, data *ShortcodeWithPage, t bundle.Template) string { buffer := new(bytes.Buffer) t.ExecuteTemplate(buffer, "shortcodes/"+name+".html", data) return buffer.String() diff --git a/hugolib/site.go b/hugolib/site.go index 0c2209cb9..5bbfc45cd 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -15,11 +15,13 @@ package hugolib import ( "bitbucket.org/pkg/inflect" - "html/template" "bytes" "fmt" "github.com/spf13/hugo/target" + helpers "github.com/spf13/hugo/template" + "github.com/spf13/hugo/template/bundle" "github.com/spf13/nitro" + "html/template" "os" "path/filepath" "strings" @@ -28,10 +30,27 @@ import ( var DefaultTimer = nitro.Initalize() +func MakePermalink(domain string, path string) string { + return strings.TrimRight(domain, "/") + "/" + strings.TrimLeft(path, "/") +} + +func mkdirIf(path string) error { + return os.MkdirAll(path, 0777) +} + +func FatalErr(str string) { + fmt.Println(str) + os.Exit(1) +} + +func PrintErr(str string, a ...interface{}) { + fmt.Fprintln(os.Stderr, str, a) +} + type Site struct { Config Config Pages Pages - Tmpl Template + Tmpl bundle.Template Indexes IndexList Files []string Sections Index @@ -83,7 +102,7 @@ func (s *Site) Analyze() { } func (s *Site) prepTemplates() { - s.Tmpl = NewTemplate() + s.Tmpl = bundle.NewTemplate() s.Tmpl.LoadTemplates(s.absLayoutDir()) } @@ -150,7 +169,6 @@ func (s *Site) initialize() { walker := func(path string, fi os.FileInfo, err error) error { if err != nil { - PrintErr("Walker: ", err) return nil } @@ -179,6 +197,18 @@ func (s *Site) initialize() { s.Shortcodes = make(map[string]ShortcodeFunc) } +// Check if File / Directory Exists +func exists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + func ignoreDotFile(path string) bool { return filepath.Base(path)[0] == '.' } @@ -420,7 +450,7 @@ func (s *Site) RenderIndexes() error { for k, o := range s.Indexes[plural] { n := s.NewNode() n.Title = strings.Title(k) - url := Urlize(plural + "/" + k) + url := helpers.Urlize(plural + "/" + k) plink := url if s.Config.UglyUrls { n.Url = url + ".html" @@ -455,9 +485,9 @@ func (s *Site) RenderIndexes() error { // XML Feed y := s.NewXMLBuffer() if s.Config.UglyUrls { - n.Url = Urlize(plural + "/" + k + ".xml") + n.Url = helpers.Urlize(plural + "/" + k + ".xml") } else { - n.Url = Urlize(plural + "/" + k + "/" + "index.xml") + n.Url = helpers.Urlize(plural + "/" + k + "/" + "index.xml") } n.Permalink = permalink(s, n.Url) s.Tmpl.ExecuteTemplate(y, "rss.xml", n) @@ -477,7 +507,7 @@ func (s *Site) RenderIndexesIndexes() (err error) { for singular, plural := range s.Config.Indexes { n := s.NewNode() n.Title = strings.Title(plural) - url := Urlize(plural) + url := helpers.Urlize(plural) n.Url = url + "/index.html" n.Permalink = permalink(s, n.Url) n.Data["Singular"] = singular @@ -503,7 +533,7 @@ func (s *Site) RenderLists() error { for section, data := range s.Sections { n := s.NewNode() n.Title = strings.Title(inflect.Pluralize(section)) - n.Url = Urlize(section + "/" + "index.html") + n.Url = helpers.Urlize(section + "/" + "index.html") n.Permalink = permalink(s, n.Url) n.RSSlink = permalink(s, section+".xml") n.Date = data[0].Date @@ -522,9 +552,9 @@ func (s *Site) RenderLists() error { if a := s.Tmpl.Lookup("rss.xml"); a != nil { // XML Feed if s.Config.UglyUrls { - n.Url = Urlize(section + ".xml") + n.Url = helpers.Urlize(section + ".xml") } else { - n.Url = Urlize(section + "/" + "index.xml") + n.Url = helpers.Urlize(section + "/" + "index.xml") } n.Permalink = template.HTML(string(n.Site.BaseUrl) + n.Url) y := s.NewXMLBuffer() @@ -539,7 +569,7 @@ func (s *Site) RenderLists() error { func (s *Site) RenderHomePage() error { n := s.NewNode() n.Title = n.Site.Title - n.Url = Urlize(string(n.Site.BaseUrl)) + n.Url = helpers.Urlize(string(n.Site.BaseUrl)) n.RSSlink = permalink(s, "index.xml") n.Permalink = permalink(s, "") if len(s.Pages) > 0 { @@ -561,7 +591,7 @@ func (s *Site) RenderHomePage() error { if a := s.Tmpl.Lookup("rss.xml"); a != nil { // XML Feed - n.Url = Urlize("index.xml") + n.Url = helpers.Urlize("index.xml") n.Title = "Recent Content" n.Permalink = permalink(s, "index.xml") y := s.NewXMLBuffer() @@ -571,7 +601,7 @@ func (s *Site) RenderHomePage() error { } if a := s.Tmpl.Lookup("404.html"); a != nil { - n.Url = Urlize("404.html") + n.Url = helpers.Urlize("404.html") n.Title = "404 Page not found" n.Permalink = permalink(s, "404.html") x, err := s.RenderThing(n, "404.html") diff --git a/hugolib/site_test.go b/hugolib/site_test.go index bbe9478b0..18b3afd7b 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -3,9 +3,9 @@ package hugolib import ( "bytes" "fmt" + "html/template" "strings" "testing" - "html/template" ) var TEMPLATE_TITLE = "{{ .Title }}" diff --git a/hugolib/summary.go b/hugolib/summary.go new file mode 100644 index 000000000..1053e1975 --- /dev/null +++ b/hugolib/summary.go @@ -0,0 +1,75 @@ +package hugolib + +import ( + "bytes" + "fmt" + "os/exec" + "strings" +) + +var summaryLength = 70 +var summaryDivider = []byte("") + +func TotalWords(s string) int { + return len(strings.Fields(s)) +} + +func WordCount(s string) map[string]int { + m := make(map[string]int) + for _, f := range strings.Fields(s) { + m[f] += 1 + } + + return m +} + +func RemoveSummaryDivider(content []byte) []byte { + return bytes.Replace(content, summaryDivider, []byte(""), -1) +} + +func TruncateWords(s string, max int) string { + words := strings.Fields(s) + if max > len(words) { + return strings.Join(words, " ") + } + + return strings.Join(words[:max], " ") +} + +func TruncateWordsToWholeSentence(s string, max int) string { + words := strings.Fields(s) + if max > len(words) { + return strings.Join(words, " ") + } + + for counter, word := range words[max:] { + if strings.HasSuffix(word, ".") || + strings.HasSuffix(word, "?") || + strings.HasSuffix(word, ".\"") || + strings.HasSuffix(word, "!") { + return strings.Join(words[:max+counter+1], " ") + } + } + + return strings.Join(words[:max], " ") +} + +func getRstContent(content []byte) string { + cleanContent := bytes.Replace(content, summaryDivider, []byte(""), 1) + + cmd := exec.Command("rst2html.py", "--leave-comments") + cmd.Stdin = bytes.NewReader(cleanContent) + var out bytes.Buffer + cmd.Stdout = &out + if err := cmd.Run(); err != nil { + fmt.Println(err) + } + + rstLines := strings.Split(out.String(), "\n") + for i, line := range rstLines { + if strings.HasPrefix(line, "") { + rstLines = (rstLines[i+1 : len(rstLines)-3]) + } + } + return strings.Join(rstLines, "\n") +} diff --git a/template/bundle/bundle_test.go b/template/bundle/bundle_test.go new file mode 100644 index 000000000..1951a71c5 --- /dev/null +++ b/template/bundle/bundle_test.go @@ -0,0 +1,12 @@ +package bundle + +import ( + "testing" +) + +func TestNothing(t *testing.T) { + b := NewTemplate() + if b.Lookup("alias") == nil { + t.Fatalf("Expecting alias to be initialized with new bundle") + } +} diff --git a/hugolib/path_seperators_windows_test.go b/template/bundle/path_seperators_windows_test.go similarity index 96% rename from hugolib/path_seperators_windows_test.go rename to template/bundle/path_seperators_windows_test.go index 5cdd7c5f6..e5f168b4f 100644 --- a/hugolib/path_seperators_windows_test.go +++ b/template/bundle/path_seperators_windows_test.go @@ -1,4 +1,4 @@ -package hugolib +package bundle import ( "testing" diff --git a/hugolib/template.go b/template/bundle/template.go similarity index 63% rename from hugolib/template.go rename to template/bundle/template.go index 8dd382379..052b2f73e 100644 --- a/hugolib/template.go +++ b/template/bundle/template.go @@ -1,19 +1,82 @@ -package hugolib +package bundle import ( - "io/ioutil" "github.com/eknkc/amber" + helpers "github.com/spf13/hugo/template" "html/template" "io" + "io/ioutil" "os" "path/filepath" + "reflect" + "strconv" "strings" ) -// HTML encapsulates a known safe HTML document fragment. -// It should not be used for HTML from a third-party, or HTML with -// unclosed tags or comments. The outputs of a sound HTML sanitizer -// and a template escaped by this package are fine for use with HTML. +func Gt(a interface{}, b interface{}) bool { + var left, right int64 + av := reflect.ValueOf(a) + + switch av.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + left = int64(av.Len()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + left = av.Int() + case reflect.String: + left, _ = strconv.ParseInt(av.String(), 10, 64) + } + + bv := reflect.ValueOf(b) + + switch bv.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + right = int64(bv.Len()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + right = bv.Int() + case reflect.String: + right, _ = strconv.ParseInt(bv.String(), 10, 64) + } + + return left > right +} + +func IsSet(a interface{}, key interface{}) bool { + av := reflect.ValueOf(a) + kv := reflect.ValueOf(key) + + switch av.Kind() { + case reflect.Array, reflect.Chan, reflect.Slice: + if int64(av.Len()) > kv.Int() { + return true + } + case reflect.Map: + if kv.Type() == av.Type().Key() { + return av.MapIndex(kv).IsValid() + } + } + + return false +} + +func ReturnWhenSet(a interface{}, index int) interface{} { + av := reflect.ValueOf(a) + + switch av.Kind() { + case reflect.Array, reflect.Slice: + if av.Len() > index { + + avv := av.Index(index) + switch avv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return avv.Int() + case reflect.String: + return avv.String() + } + } + } + + return "" +} type Template interface { ExecuteTemplate(wr io.Writer, name string, data interface{}) error @@ -41,7 +104,7 @@ func NewTemplate() Template { } funcMap := template.FuncMap{ - "urlize": Urlize, + "urlize": helpers.Urlize, "gt": Gt, "isset": IsSet, "echoParam": ReturnWhenSet, @@ -85,10 +148,13 @@ func (t *GoHtmlTemplate) primeTemplates() { t.AddTemplate("alias-xhtml", alias_xhtml) } +func ignoreDotFile(path string) bool { + return filepath.Base(path)[0] == '.' +} + func (t *GoHtmlTemplate) LoadTemplates(absPath string) { walker := func(path string, fi os.FileInfo, err error) error { if err != nil { - PrintErr("Walker: ", err) return nil } @@ -108,7 +174,6 @@ func (t *GoHtmlTemplate) LoadTemplates(absPath string) { // note t.New(tplName) if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil { - PrintErr("Could not compile amber file: "+path, err) return err } diff --git a/template/helpers.go b/template/helpers.go new file mode 100644 index 000000000..d12ffd96c --- /dev/null +++ b/template/helpers.go @@ -0,0 +1,29 @@ +// Copyright © 2013 Steve Francia . +// +// 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 obtain a copy of the License at +// http://opensource.org/licenses/Simple-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 template + +import ( + "regexp" + "strings" +) + +var sanitizeRegexp = regexp.MustCompile("[^a-zA-Z0-9./_-]") + +func Urlize(url string) string { + return Sanitize(strings.ToLower(strings.Replace(strings.TrimSpace(url), " ", "-", -1))) +} + +func Sanitize(s string) string { + return sanitizeRegexp.ReplaceAllString(s, "") +}