package blog import ( "bytes" "fmt" "git.gutmet.org/goutil.git" . "git.gutmet.org/wombat.git/templatestructures" "math" "os" "path" "path/filepath" "sort" "strconv" "strings" "text/template" "time" ) const postsPerPage int = 5 var blogname string var folder string var style string var templateString string var t *template.Template var categories map[string][]post type metadata struct { Title string Date time.Time Categories []string } type post struct { Content string Meta metadata Filename string Link string } type categoryListing struct { Name string ASCIIName string Posts []post } func linkToPost(filename string) string { filename = filepath.Base(filename) split := strings.Split(filename, "-") if len(split) < 4 { return "" } else { year := split[0] month := split[1] day := split[2] name := ConvASCII(strings.Join(split[3:], "-")) return fmt.Sprintf("/%s/%s/%s/%s/%s", folder, year, month, day, name) } } func linkToCategory(name string) string { return fmt.Sprintf("/%s/categories.html#%s", folder, ConvASCII(strings.ToLower(name))) } func addToCategory(category string, post post) { c := strings.ToLower(category) if len(c) > 0 { categories[c] = append(categories[c], post) } } func keys(m map[string][]post) []string { keys := make([]string, 0) for k := range m { keys = append(keys, k) } return keys } func emitPostPage(post post) string { filename := strings.TrimPrefix(strings.TrimPrefix(post.Filename, "stage1/"), "stage1\\") link := post.Link os.Remove(filepath.Join("stage2", filename)) base := path.Base(link) folders := strings.TrimSuffix("stage2"+link, base) os.MkdirAll(folders, 0755) page := Page{} page.Blogname = blogname page.Title = post.Meta.Title page.Style = style page.Content = post.Content page.Time = post.Meta.Date.Format(TimeFormat) page.Blogpost = true for _, categoryName := range post.Meta.Categories { page.Categories = append(page.Categories, Category{categoryName, linkToCategory(categoryName)}) addToCategory(categoryName, post) } buf := new(bytes.Buffer) t.Execute(buf, page) goutil.WriteFile(filepath.Join("stage2", link), buf.String()) return link } func indexFilename(i int) string { return filepath.Join("stage2", folder, fmt.Sprintf("%d.html", i)) } func indexPageExists(i int, total int) bool { max := int(math.Ceil(float64(total)/float64(postsPerPage))) - 1 return (i >= 0) && (i <= max) } type byDateDesc []post func (p byDateDesc) Len() int { return len(p) } func (p byDateDesc) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p byDateDesc) Less(i, j int) bool { return p[i].Meta.Date.After(p[j].Meta.Date) } func emitIndexPage(i int, posts []post, total int) { file := indexFilename(i) postCollection := make([]Blogpost, 0) sort.Sort(byDateDesc(posts)) for _, post := range posts { link := emitPostPage(post) p := Blogpost{} p.Title = post.Meta.Title p.Link = link p.Content = post.Content postCollection = append(postCollection, p) } buf := new(bytes.Buffer) page := Page{} page.Title = blogname page.Style = style page.Blogdir = folder page.Blogpost = false page.PostCollection = postCollection if indexPageExists(i-1, total) { page.Previous = strconv.Itoa(i-1) + ".html" } if indexPageExists(i+1, total) { page.Later = strconv.Itoa(i+1) + ".html" } t.Execute(buf, page) goutil.WriteFile(file, buf.String()) } func getMetadata(file string) (metadata, error) { metaAll, err := goutil.ReadFile(goutil.TrimExt(file) + ".desc") ret := metadata{} if err == nil { lines := strings.Split(metaAll, "\n") for _, line := range lines { if strings.HasPrefix(line, "title:") { ret.Title = strings.Trim(strings.TrimPrefix(line, "title:"), "\" ") } else if strings.HasPrefix(line, "date:") { date, err2 := time.Parse(TimeFormat, strings.Trim(strings.TrimPrefix(line, "date:"), "\" ")) if err2 == nil { ret.Date = date } else { fmt.Printf("Unrecognized date format in %s", file) } } else if strings.HasPrefix(line, "categories:") { categories := strings.Trim(strings.TrimPrefix(line, "categories:"), "\"[] ") splitcategories := strings.Split(categories, ",") for _, category := range splitcategories { c := strings.TrimSpace(category) if len(c) > 0 { ret.Categories = append(ret.Categories, c) } } } } return ret, nil } else { return ret, err } } func getPost(file string) (post, error) { tmp, err := goutil.ReadFile(file) if err == nil { meta, err2 := getMetadata(file) if err2 == nil { p := post{} p.Content = tmp p.Meta = meta p.Filename = file filename := strings.TrimPrefix(file, "stage1") p.Link = linkToPost(filename) return p, nil } else { return post{}, err2 } } else { return post{}, err } } func makeCategories() { ct := template.Must(template.New("Categories").Parse(categoryTemplate)) page := Page{} page.Title = blogname + ": Categories" page.Style = style keySet := keys(categories) sort.Strings(keySet) page.Content += "