github.com/elves/elvish@v0.15.0/website/cmd/genblog/blog.go (about)

     1  package main
     2  
     3  import (
     4  	"io/ioutil"
     5  	"log"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/BurntSushi/toml"
    11  )
    12  
    13  // This file contains functions and types for parsing and manipulating the
    14  // in-memory representation of the blog.
    15  
    16  // blogConf represents the global blog configuration.
    17  type blogConf struct {
    18  	Title      string
    19  	Author     string
    20  	Categories []categoryMeta
    21  	Index      articleMeta
    22  	FeedPosts  int
    23  	RootURL    string
    24  	Template   string
    25  	BaseCSS    []string
    26  }
    27  
    28  // categoryMeta represents the metadata of a cateogory, found in the global
    29  // blog configuration.
    30  type categoryMeta struct {
    31  	Name  string
    32  	Title string
    33  }
    34  
    35  // categoryConf represents the configuration of a category. Note that the
    36  // metadata is found in the global blog configuration and not duplicated here.
    37  type categoryConf struct {
    38  	Prelude   string
    39  	AutoIndex bool
    40  	ExtraCSS  []string
    41  	ExtraJS   []string
    42  	Articles  []articleMeta
    43  }
    44  
    45  // articleMeta represents the metadata of an article, found in a category
    46  // configuration.
    47  type articleMeta struct {
    48  	Name      string
    49  	Title     string
    50  	Timestamp string
    51  	ExtraCSS  []string
    52  	ExtraJS   []string
    53  }
    54  
    55  // article represents an article, including all information that is needed to
    56  // render it.
    57  type article struct {
    58  	articleMeta
    59  	IsHomepage   bool
    60  	Category     string
    61  	Content      string
    62  	ExtraCSS     string
    63  	ExtraJS      string
    64  	LastModified rfc3339Time
    65  }
    66  
    67  type recentArticles struct {
    68  	articles []article
    69  	max      int
    70  }
    71  
    72  func (ra *recentArticles) insert(a article) {
    73  	// Find a place to insert.
    74  	var i int
    75  	for i = len(ra.articles); i > 0; i-- {
    76  		if ra.articles[i-1].Timestamp > a.Timestamp {
    77  			break
    78  		}
    79  	}
    80  	// If we are at the end, insert only if we haven't reached the maximum
    81  	// number of articles.
    82  	if i == len(ra.articles) {
    83  		if i < ra.max {
    84  			ra.articles = append(ra.articles, a)
    85  		}
    86  		return
    87  	}
    88  	// If not, make space and insert.
    89  	if len(ra.articles) < ra.max {
    90  		ra.articles = append(ra.articles, article{})
    91  	}
    92  	copy(ra.articles[i+1:], ra.articles[i:])
    93  	ra.articles[i] = a
    94  }
    95  
    96  // decodeFile decodes the named file in TOML into a pointer.
    97  func decodeTOML(fname string, v interface{}) {
    98  	_, err := toml.DecodeFile(fname, v)
    99  	if err != nil {
   100  		log.Fatalln(err)
   101  	}
   102  }
   103  
   104  func readFile(fname string) string {
   105  	content, err := ioutil.ReadFile(fname)
   106  	if err != nil {
   107  		log.Fatal(err)
   108  	}
   109  	return string(content)
   110  }
   111  
   112  func catInDir(dirname string, fnames []string) string {
   113  	var sb strings.Builder
   114  	for _, fname := range fnames {
   115  		sb.WriteString(readFile(filepath.Join(dirname, fname)))
   116  	}
   117  	return sb.String()
   118  }
   119  
   120  func getArticle(a article, am articleMeta, dir string) article {
   121  	fname := filepath.Join(dir, am.Name+".html")
   122  	content := readFile(fname)
   123  	fileInfo, err := os.Stat(fname)
   124  	if err != nil {
   125  		log.Fatal(err)
   126  	}
   127  	modTime := fileInfo.ModTime()
   128  	css := catInDir(dir, am.ExtraCSS)
   129  	js := catInDir(dir, am.ExtraJS)
   130  	return article{
   131  		am, a.IsHomepage, a.Category, content, css, js, rfc3339Time(modTime)}
   132  }